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

Topic Exchange

topic exchange match routing key ของ message กับ pattern ในแต่ละ binding เป็น exchange type ที่ยืดหยุ่นที่สุด: direct คือ “เท่ากัน”, fanout คือ “ทั้งหมด” และ topic คือ “match รูปทรงนี้” topic จึงเปิดให้ subscriber บอกว่า “ฉันอยากได้ event แบบเหล่านี้” โดยที่ producer ไม่ต้องรู้ว่าใครฟังอยู่

routing key มีโครงสร้างเป็น word คั่นด้วยจุด: order.created, payment.failed.th, sensor.temperature.warehouse-3 ส่วน binding key ใช้รูปแบบ dotted เดียวกันบวก wildcard สองตัว:

  • * (star) match หนึ่ง word พอดี
  • # (hash) match ศูนย์ word ขึ้นไป
flowchart LR
  p["publish
'order.eu.created'"] --> x["topic exchange
'events'"]
  x -->|"order.*.created"| q1["queue: new-orders"]
  x -->|"order.#"| q2["queue: all-order-events"]
  x -. "ไม่ match: payment.#" .-> q3["queue: payments"]
topic exchange match key แบบ dotted กับ binding pattern

ลองไล่ key order.eu.created:

  • order.*.createdmatch (* กลืน eu, word แรกและท้ายเป็น literal)
  • order.#match (# กลืน eu.created, กี่ word ตามหลังก็ได้)
  • payment.#ไม่ match (word แรกต้องเป็น payment)
  • order.*ไม่ match (* คือ word เดียวพอดี แต่หลัง order มีสอง word)

อันสุดท้ายคือกับดักคลาสสิก: * คือ หนึ่ง word พอดี ไม่ใช่ “หนึ่งขึ้นไป” ถ้าความยาวส่วนท้ายไม่แน่นอนให้ใช้ #

const ex = 'events';
await channel.assertExchange(ex, 'topic', { durable: true });
// "all created orders, in any region"
const q = await channel.assertQueue('new-orders', { durable: true });
await channel.bindQueue(q.queue, ex, 'order.*.created');
// producer: the routing key describes the event
channel.publish(ex, 'order.eu.created', Buffer.from('...'));

topic exchange เลียนแบบอีกสอง type ได้:

  • binding key ที่ ไม่มี wildcard (order.created) ทำงานเหมือน binding แบบ direct เป๊ะ
  • binding key ที่เป็นแค่ # match ทุกอย่าง ทำงานเหมือน fanout

ดังนั้น หลายทีมจึงตั้ง topic exchange เป็น default สำหรับ event bus — ไม่มีต้นทุนเพิ่มและเหลือที่ให้เพิ่ม subscriber ที่ละเอียดขึ้นทีหลัง trade-off คือวินัย: routing-key scheme ที่ดีและสม่ำเสมอ (domain.detail.action) คือสิ่งที่ทำให้ topic routing อ่านง่ายแทนที่จะยุ่งเหยิง

ใน topic exchange wildcard * match อะไร?
binding pattern ไหน match routing key "payment.failed.th"?
topic exchange ทำตัวเหมือน fanout exchange ได้อย่างไร?
ทำไมหลายทีมตั้ง topic exchange เป็น default ของ event bus?