🎯 什麼情境該想到我

當你「想依某些規則把訊息導向不同的接收者/通道,又不想讓發送方知道這些接收者是誰」的時候。

⚙️ 怎麼用(步驟 / 公式)

意圖:用一個專責元件,依規則把訊息從輸入通道轉送到正確的輸出通道,但不改變訊息內容。

做法 / 結構要點:

  • 路由器從輸入通道取訊息,依判斷條件(訊息內容、標頭、系統狀態等)選一個輸出通道送出。
  • 它只決定「去哪」,不動訊息本體。
  • 把路由邏輯集中在一處,發送方與接收方彼此解耦,可獨立增減接收方。

★★ 最重要的一個設計決定:路由規則放在哪

這是整個路由家族真正的難題,EIP 書裡談得很少。

放哪優點★ 代價
① 寫死在路由器程式碼裡簡單、可測、可版控改規則要重新部署
② 設定檔/資料庫不用重新部署★ 規則變成沒有型別檢查的資料,改錯了執行期才知道
③ broker 的路由能力零程式碼★ 拓撲變成基礎設施設定,不在 git 裡,沒人看得懂
④ ★ 不要路由器:讓消費者自己過濾最簡單每個消費者都收到全部訊息(量大時浪費)

★ 判準:這個規則多久改一次?
很少改(一季一次)→ ①,寫在程式碼裡。規則是邏輯,就該像邏輯一樣被 review 和測試。
經常改(營運人員要調)→ ② 或 ③,但必須配上「規則的測試」與「規則變更的審計」。

⚠️ 最常見的失敗:選了 ③,然後兩年後沒有人知道訊息為什麼會流到那裡。
RabbitMQ 的 exchange/binding 拓撲特別容易變成這樣——它不在任何 repo 裡。
→ 至少要讓拓撲由程式碼宣告(IaC/啟動時 declare),見 隨選環境與基礎設施即程式碼。

★ 各家 broker 內建的路由能力(很多時候你不用自己寫)

broker內建路由
RabbitMQ★ 最強:direct(精確 routing key)/topic(order.*.created 通配)/fanout/headers exchange
SNS★ 訂閱篩選政策(filter policy)依訊息屬性過濾
Kafka★ 幾乎沒有——分區由 key 決定,跨 topic 路由要靠 Kafka Streams 或自己寫消費者
NATS主題通配(orders.*.placed、orders.>)

★ Kafka 沒有內建路由,是選型時最常被低估的差異。
「依內容分流到不同 topic」在 Kafka 裡就是一個你要自己寫、自己部署、自己監控的服務。

★ Go 的實作:路由器就是一個消費者 + 一個生產者

// ★ 路由器必須是無狀態的 —— 這樣才能水平擴展、隨意重啟
func route(msg Envelope) (topic string, err error) {
    switch msg.Type {                       // ★ 只看標頭,不解 body(見 [[訊息]])
    case "orders.order.placed":   return "fulfilment.inbound", nil
    case "orders.order.canceled": return "refunds.inbound", nil
    }
    return "", fmt.Errorf("no route for type %q", msg.Type)   // ★ 一定要處理「沒有路由」
}
 
// ★★ 沒有匹配的規則時,絕對不要靜默丟棄
if topic, err := route(msg); err != nil {
    return publish(ctx, invalidMessageChannel, msg)   // ★ 見 [[無效訊息通道]]
}

★★ 「沒有匹配路由」的處理是路由器最常見的 bug:
靜默 drop → 訊息人間蒸發,而且沒有任何指標會顯示這件事。
一定要送 無效訊息通道 並加計數器告警。

★ 兄弟辨析:整個路由家族一次看懂

模式輸入 → 輸出有狀態?一句話
內容路由器1 → 1無依內容選一個目的地
訊息過濾器1 → 0 或 1無不符條件就丟掉
收件人清單1 → N無依規則算出一份清單,全部送
分割器1 → N無依內容項目拆成多則
聚合器N → 1★ 有收齊後合併
重排序器N → N★ 有只排序,不合併
動態路由器1 → 1★ 有(路由表)目的地自己來註冊
路由單1 → 1無(狀態在訊息裡)★ 路徑寫在訊息上
流程管理器1 → N(多回合)★ 有中央協調,可分支、可等待

★ 有狀態的三個(聚合器、重排序器、流程管理器)是這個家族真正困難的部分——
它們需要處理逾時、記憶體上限、重啟後的狀態恢復。無狀態的那些幾乎都是十行程式碼。

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 路由器是有狀態或需維護規則的元件,可能成為瓶頸或單點;規則過多會難維護。

  • 若只是要改資料格式而非分流,那是轉換器的工作,不要混在一起。

  • ★★ 「沒有匹配路由」絕對不要靜默丟棄。要送 無效訊息通道 並加計數器告警,否則訊息會人間蒸發。

  • ★★ 路由規則放在 broker 設定裡,兩年後沒人看得懂。至少讓拓撲由程式碼宣告。

  • ★ Kafka 幾乎沒有內建路由。「依內容分流」在 Kafka 是一個你要自己寫、部署、監控的服務。

  • ★ 路由器要無狀態,才能水平擴展與隨意重啟。有狀態的需求請用 聚合器/流程管理器。

  • ★ 路由器不該解開 body。只看標頭,否則 schema 一改就要改路由器。

  • 路由器是額外一跳:多一次延遲、多一個會掛的元件。能讓消費者自己過濾時就不要加路由器。

  • 規則放設定檔就失去型別檢查。改錯了執行期才知道 → 要有規則的測試。

🔗 相關工具