ข้ามไปยังเนื้อหา

Keyspace Notifications

Redis สามารถ publish ข้อความ Pub/Sub ได้ทุกครั้งที่เกิด event บางอย่าง — เช่น key หมดอายุ, มีการรัน SET, มีการรัน DEL และอื่น ๆ แอปพลิเคชันของคุณ subscribe ช่องทางเหล่านี้เพื่อตอบสนองโดยไม่ต้อง polling: ตัวอย่างเช่น ล้าง local cache เมื่อ key หมดอายุ หรือเรียก background job เมื่อมีการเขียน key เฉพาะ

Redis เปิดเผยช่องทาง 2 ประเภท:

  • Keyevent channels — หนึ่งช่องทางต่อประเภท event; payload ของข้อความคือชื่อ key รูปแบบ: __keyevent@<db>__:<event> (ตัวอย่าง: __keyevent@0__:expired)
  • Keyspace channels — หนึ่งช่องทางต่อ key; payload ของข้อความคือประเภท event รูปแบบ: __keyspace@<db>__:<keyname>

Keyspace notifications ถูกปิดใช้งานโดยค่าเริ่มต้น เนื่องจากการ publish ทุก event จะเพิ่มภาระ CPU เปิดใช้งานด้วย CONFIG SET ขณะรันไทม์ หรือผ่าน redis.conf เมื่อเริ่มต้น

ค่าที่กำหนดคือสตริงของอักขระ flag ที่เลือกว่าจะ publish event class ใดบ้าง:

FlagEvents ที่เปิดใช้งาน
KKeyspace events (ช่องทาง __keyspace@...)
EKeyevent events (ช่องทาง __keyevent@...)
xExpired events (TTL ของ key ถึงศูนย์)
gคำสั่งทั่วไป: DEL, EXPIRE, RENAME, …
sคำสั่ง Set (SADD, SREM, …)
lคำสั่ง List (LPUSH, RPOP, …)

สำหรับ expiry notifications ใน production การตั้งค่าที่นิยมใช้คือ Ex — keyevent channel (E) สำหรับ expired events เท่านั้น (x):

notify-keyspace-events "Ex"

หรือขณะรันไทม์:

127.0.0.1:6379> CONFIG SET notify-keyspace-events Ex
OK

Keyspace notifications ใช้การทำงานแบบสอง terminal เปิด Terminal 1 และ subscribe ก่อนที่ key จะหมดอายุ:

127.0.0.1:6379> PSUBSCRIBE __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)

ใน Terminal 2 กำหนด key ที่มี TTL สั้น ๆ เพื่อ trigger event:

127.0.0.1:6379> SET demo:token "abc" EX 3
OK

หลังจาก 3 วินาที Terminal 1 จะได้รับการแจ้งเตือน:

1) "pmessage"
2) "__keyevent@0__:expired"
3) "__keyevent@0__:expired"
4) "demo:token"

บรรทัดที่สี่คือชื่อ key — ตอนนี้ subscriber ของคุณรู้แน่ชัดว่า key ไหนหมดอายุ

คำสั่งด้านล่างเปิดใช้งาน notifications และกำหนด key ที่มี TTL เพื่อให้คุณสังเกตการกำหนดค่าในการทำงาน หากต้องการดู expired event ให้เปิด redis-cli ตัวที่สอง รัน PSUBSCRIBE __keyevent@0__:expired จากนั้นใน terminal แรกรัน SET demo:token "hello" EX 5 แล้วรอ 5 วินาที

CONFIG SET notify-keyspace-events Ex
SET demo:token "hello" EX 5
TTL demo:token

เนื่องจาก Pub/Sub ต้องการสอง connections พร้อมกัน ให้ทำ workflow สอง terminal ในสภาพแวดล้อม redis-cli ของคุณเองเพื่อดู expired event ในแบบ real time

ตัวเลือกBenefitCost
Keyevent channel เฉพาะ event ที่ใช้ (เช่น Ex)overhead ต่ำ เปิดเฉพาะสิ่งที่จำเป็นต้องเลือก flag ให้ครบ ไม่ครอบคลุมเหตุการณ์อื่นที่อาจต้องใช้ทีหลัง
Flag กว้าง เช่น KEA (ทุก event)ครอบคลุมทุกกรณีโดยไม่ต้องแก้ config เพิ่มเพิ่มภาระ CPU ที่วัดได้บน workload ที่เขียนหนัก เพราะ publish ทุก event
Pub/Sub-based notification แทน pollingไม่ต้อง query ซ้ำ ๆ ลด load บน serverPub/Sub ไม่มี delivery guarantee — ถ้า subscriber ไม่ได้ online ตอน event เกิด ข้อความนั้นหายไปเลย
  • เข้าใจผิดว่า expired event ส่งมาทันทีที่ TTL หมดพอดี — Redis ใช้ lazy expiry (ตรวจตอนเข้าถึง key) ผสมกับ active expiry (สุ่มตรวจเป็นรอบ) เวลาที่ event ถูก publish จริงอาจช้ากว่าเวลาที่ TTL หมดเล็กน้อย ไม่ควรใช้เป็นนาฬิกาที่แม่นยำ
  • พึ่งพา keyspace notification เป็นกลไก reliable messaging — Pub/Sub ไม่เก็บ history และไม่ redeliver หาก subscriber หลุดการเชื่อมต่อชั่วขณะ event ที่เกิดระหว่างนั้นจะหายไปถาวร ถ้าต้องการ delivery guarantee ควรใช้ Streams แทน
  • เปิด flag KEA แบบ catch-all ใน production โดยไม่จำเป็น — การ publish ทุก event บน workload ที่เขียนหนักเพิ่มภาระ CPU อย่างมีนัยสำคัญ ควรเปิดเฉพาะ event class ที่แอปใช้งานจริง

💡 ตัวอย่างจากของจริง

E-commerce cart abandonment — ระบบ e-commerce หลายเจ้าใช้ expired keyspace event เพื่อ trigger การส่งอีเมลเตือนเมื่อ cart session หมดอายุโดยไม่มีการ checkout

Session cleanup services — บริการที่เก็บ session ใน Redis ใช้ keyspace notification เพื่อล้าง cache ฝั่ง application หรือ log-out ผู้ใช้จากระบบอื่นทันทีที่ session key หมดอายุ แทนที่จะต้อง polling ตรวจสอบเป็นระยะ

CONFIG flag ใดที่เปิดใช้งาน keyevent channels (`__keyevent@...`)?
รูปแบบช่องทางใดที่ส่ง expiry events บน database 0?
Keyspace notifications ถูกเปิดใช้งานโดยค่าเริ่มต้นใน Redis หรือไม่?
รูปแบบ PSUBSCRIBE ใดที่ match กับ keyevent channels ทั้งหมดบน database 0?