Lists เป็น Queue และ Stack
FIFO Queue — LPUSH + RPOP
หัวข้อที่มีชื่อว่า “FIFO Queue — LPUSH + RPOP”Queue จะประมวลผลข้อมูลตามลำดับ first-in, first-out คือสิ่งที่เข้ามาก่อนจะออกไปก่อน ด้วย Redis List: ฝั่ง producer ใช้ LPUSH (เพิ่มที่หัวลิสต์) และฝั่ง consumer ใช้ RPOP (ดึงจากท้ายลิสต์) เนื่องจาก LPUSH เพิ่มข้อมูลที่หัวเสมอ รายการที่เก่าที่สุดจึงอยู่ที่ท้ายเสมอ ซึ่งตรงกับตำแหน่งที่ RPOP อ่านออกมาพอดี
127.0.0.1:6379> LPUSH jobs "job:1"(integer) 1127.0.0.1:6379> LPUSH jobs "job:2"(integer) 2127.0.0.1:6379> LPUSH jobs "job:3"(integer) 3127.0.0.1:6379> RPOP jobs"job:1"127.0.0.1:6379> RPOP jobs"job:2"job:1 ถูก push เข้ามาก่อน จึงออกไปก่อน — นี่คือ FIFO
LPUSH jobs "job:1"
LPUSH jobs "job:2"
LPUSH jobs "job:3"
RPOP jobs
RPOP jobsStack — LPUSH + LPOP
หัวข้อที่มีชื่อว่า “Stack — LPUSH + LPOP”Stack จะประมวลผลข้อมูลตามลำดับ last-in, first-out คือสิ่งที่เข้ามาหลังสุดจะออกไปก่อน ทั้ง push และ pop เกิดขึ้นที่ปลายเดียวกัน (หัวของลิสต์) ดังนั้นรายการที่ push ล่าสุดจึงเป็นรายการถัดไปที่จะถูกดึงออกเสมอ
127.0.0.1:6379> DEL stack(integer) 0127.0.0.1:6379> LPUSH stack "frame:1"(integer) 1127.0.0.1:6379> LPUSH stack "frame:2"(integer) 2127.0.0.1:6379> LPUSH stack "frame:3"(integer) 3127.0.0.1:6379> LPOP stack"frame:3"127.0.0.1:6379> LPOP stack"frame:2"DEL stack
LPUSH stack "frame:1"
LPUSH stack "frame:2"
LPUSH stack "frame:3"
LPOP stack
LPOP stackRPOPLPUSH — ย้ายข้อมูลระหว่างลิสต์แบบ atomic
หัวข้อที่มีชื่อว่า “RPOPLPUSH — ย้ายข้อมูลระหว่างลิสต์แบบ atomic”RPOPLPUSH source destination จะดึงข้อมูลจากท้ายของ source และเพิ่มไปที่หัวของ destination ในการทำงาน atomic เพียงครั้งเดียว นี่คือ pattern คลาสสิกสำหรับ reliable queue: งานจะถูกย้ายจากลิสต์ pending ไปยัง processing ในขั้นตอนเดียว จึงไม่มีทางเกิดปัญหาหากเกิด crash ขึ้นระหว่างกลาง
127.0.0.1:6379> DEL pending processing(integer) 0127.0.0.1:6379> RPUSH pending "task:A" "task:B" "task:C"(integer) 3127.0.0.1:6379> RPOPLPUSH pending processing"task:A"127.0.0.1:6379> LRANGE pending 0 -11) "task:B"2) "task:C"127.0.0.1:6379> LRANGE processing 0 -11) "task:A"task:A อยู่ที่ท้ายของ pending (ถูก push เข้ามาก่อนด้วย RPUSH) หลังจาก RPOPLPUSH จะไปอยู่ที่หัวของ processing ส่วน pending เหลือแค่รายการที่ยังไม่ถูกหยิบ
DEL pending processing
RPUSH pending "task:A" "task:B" "task:C"
RPOPLPUSH pending processing
LRANGE pending 0 -1
LRANGE processing 0 -1Blocking pop — BLPOP และ BRPOP
หัวข้อที่มีชื่อว่า “Blocking pop — BLPOP และ BRPOP”BLPOP key [key ...] timeout จะบล็อก connection ไว้จนกว่าจะมีข้อมูล แล้วจึงดึงจากลิสต์แรกที่ไม่ว่างเปล่า BRPOP ทำงานเหมือนกันแต่ดึงจากท้ายลิสต์ timeout ที่เป็น 0 หมายความว่ารอไปเรื่อยๆ ไม่มีกำหนด
127.0.0.1:6379> BLPOP jobs 51) "jobs"2) "job:3"
(if jobs is empty, the client blocks for up to 5 seconds)หมายเหตุ: BLPOP ต้องใช้กับ connection แบบ blocking สด — ทดสอบใน redis-cli ของคุณเอง
ใน worker process คุณจะรัน BLPOP jobs 0 วนซ้ำในลูป เมื่อ producer เรียก LPUSH jobs "new-job" การเรียกแบบ blocking จะ return ทันทีพร้อมกับงานใหม่ — ไม่ต้อง polling แต่อย่างใด
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
BLPOP/BRPOP (blocking pop) | ไม่ต้องเขียน polling loop เอง worker ตื่นทันทีเมื่อมีงานใหม่ | ต้องเปิด connection ทิ้งไว้บล็อกยาว ๆ ต่อ worker หนึ่งตัว |
| Redis List เป็น queue | ตั้งค่าง่าย latency ต่ำ ไม่ต้องติดตั้ง broker แยก | ไม่มี retry, dead-letter, หรือ delivery guarantee ในตัวเหมือน RabbitMQ/Kafka |
RPOPLPUSH ย้ายไป processing list | ป้องกันงานหายถ้า worker crash ระหว่างประมวลผล | ต้องเขียน logic เคลียร์ processing list เองเมื่อ worker ทำงานเสร็จ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ใช้
RPOPLPUSHย้ายงานไป processing list แต่ไม่เคลียร์ออกเมื่อประมวลผลเสร็จ — processing list โตขึ้นเรื่อย ๆ จนกลายเป็น memory leak - ใช้ Redis List queue แทน message broker เต็มรูปแบบเมื่อจำเป็นต้องมี retry, dead-letter queue หรือ delivery guarantee ที่เข้มงวด — Redis List ไม่มี feature เหล่านี้ในตัว ต้องเขียนเองทั้งหมด
- ปล่อย unbounded list โดยไม่
LTRIM— ถ้า consumer ตามไม่ทัน producer list จะโตไม่มีขีดจำกัดจนหน่วยความจำหมด
💡 ตัวอย่างจากของจริง
Sidekiq — background job library ยอดนิยมของ Ruby ใช้ Redis List เป็น queue หลัก โดยมี worker process วน
BLPOPรอรับงานใหม่แบบเดียวกับที่เรียนในบทนี้GitHub — ใช้ Redis-backed queue (ผ่าน Sidekiq) ประมวลผล background job อย่างการส่ง notification และ webhook นับล้านครั้งต่อวัน