🎯 什麼情境該想到我

當你「要根據訊息的內容,把它送到正確的目的通道」的時候。

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

意圖:以訊息的內容為依據,將它路由到不同的通道。

做法要點:

  • 路由器檢查訊息內容(某些欄位、型別、值等)。
  • 依照預定規則決定唯一的輸出通道,並把訊息原樣轉送。
  • 不改動訊息內容,只決定去向。
  • 適用於處理步驟由不同系統負責、或資料需依類別分流的情境。

★ Go 的實作:三十行就是一個內容路由器

type Route struct {
    Match func(Envelope) bool
    Topic string
}
 
var routes = []Route{
    {func(e Envelope) bool { return e.Type == "orders.order.placed" }, "fulfilment.inbound"},
    {func(e Envelope) bool { return e.Type == "orders.order.canceled" }, "refunds.inbound"},
}
 
func route(ctx context.Context, e Envelope, msg Message) error {
    for _, r := range routes {
        if r.Match(e) { return publish(ctx, r.Topic, msg) }
    }
    // ★★ 沒有匹配 —— 絕對不要靜默 return nil
    metrics.Unroutable.WithLabelValues(e.Type).Inc()
    return publish(ctx, invalidMessageChannel, msg)
}

★★ 「沒有匹配路由」是內容路由器的頭號 bug:
靜默 drop → 訊息人間蒸發,而且沒有任何指標會顯示這件事。
→ 一定要送 無效訊息通道 + 加上帶 type 標籤的計數器。

★★ 先問:能不能不要路由器?

★ 三種「不需要路由器」的替代方案,成本都更低:
① 生產者直接發到正確的通道(★ 它通常知道自己在發什麼)
② ★ 用 broker 的原生路由(RabbitMQ topic exchange、SNS filter policy)—— 零程式碼
③ ★ 讓消費者用 [[選擇性消費者]] 自己過濾 —— 零額外元件

★ 路由器是額外一跳:多一次延遲、多一個部署單元、多一個會掛的元件、
多一段「訊息為什麼沒到」的可能原因。
★ 判準:路由規則是「跨越多個生產者的共同決策」嗎?
不是(單一生產者就知道要發哪裡)→ 不要加路由器。

⚠️ Kafka 幾乎沒有內建路由(見 訊息路由器),所以在 Kafka 上「依內容分流」
就是一個你要自己寫、部署、監控的服務——這讓上面的判準更重要。

★ 路由規則放哪:預設放程式碼

放哪什麼時候
★ 寫在程式碼裡預設選擇。規則是邏輯,就該被 review、被測試、被版控
設定檔/DB營運人員要在不部署的情況下調整。★ 必須配規則的測試與變更審計
broker 拓撲規則很簡單且穩定。★ 但拓撲要由 IaC 宣告,不要手動點

★★ 三個實務上的硬要求

① ★ 無狀態
   路由器不該記任何東西 → 可以隨意水平擴展、隨意重啟
   有狀態的需求(等齊、排序)→ 那是 [[聚合器]]/[[重排序器]],不是路由器

② ★ 只看標頭,不解 body
   解 body 才能決定去向 → ★ 路由器被每一種 schema 綁死,schema 一改就要改它
   → 需要的路由依據要「提升到標頭」(見 [[訊息]]、[[信封包裝器]])

③ ★★ 路由器本身要冪等/可重送
   路由器發出訊息後、ack 來源前崩潰 → 重送 ⇒ 下游收到兩份
   → ★ 下游必須冪等([[冪等接收者]])。路由器無法自己解決這件事

★ 兄弟辨析(一個輸入、一個輸出 vs 其他)

輸出差別
內容路由器恰好 1依內容選一個目的地
訊息過濾器0 或 1★ 不符條件就丟掉,沒有「另一個目的地」
收件人清單N★ 算出一份清單,全部都送
分割器N★ 依內容項目拆成多則(不是複製)
動態路由器1★ 路由表由目的地自己註冊,不是寫死
路由單1★ 路徑寫在訊息裡,路由器只看下一站

🧪 我實際套用的紀錄

  • (待填)

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

  • 路由器需知道所有可能目的地與判斷規則,容易變成維護熱點。

  • 規則寫死時,新增目的地就得改路由器——可改用動態路由器。

  • 只會選一個目的地;若要送給多個,用收件人清單。

  • ★★ 「沒有匹配路由」絕對不要靜默丟棄。 送 無效訊息通道 + 加帶 type 標籤的計數器。

  • ★★ 先問能不能不要路由器:生產者直接發、broker 原生路由、消費者自己過濾——三者成本都更低。

  • ★ 路由器只看標頭,不解 body。解 body 就被每種 schema 綁死。

  • ★ 路由器要無狀態,才能水平擴展與隨意重啟。

  • ★ 路由器重送會讓下游收到兩份。下游必須冪等,路由器自己解決不了。

  • ★ 路由規則預設放程式碼。放設定檔就失去型別檢查,改錯執行期才知道。

  • ★ Kafka 幾乎沒有內建路由,這裡的每一個路由器都是一個要維運的服務。

  • 路由器是額外一跳:多延遲、多一個會掛的元件、多一種「訊息為什麼沒到」的原因。

🔗 相關工具