🎯 什麼情境該想到我
當你「有兩套不同的訊息系統(不同廠牌/平台),需要讓訊息在它們之間流通」的時候。
⚙️ 怎麼用(步驟 / 公式)
意圖:用一個橋接元件連接兩套訊息系統,把一邊通道上的訊息複製/轉送到另一邊的通道。
做法 / 結構要點:
- 橋接同時是兩套訊息系統的端點:從系統 A 的通道取訊息,送到系統 B 的對應通道(反向亦然)。
- 過程中依需要做必要的格式或協定轉換,讓兩邊都能理解。
- 應用程式各自仍只面對自己熟悉的訊息系統,跨系統的細節由橋接吸收。
★ 什麼時候真的需要橋接(四個實際場景)
| 場景 | 例子 |
|---|---|
| ① ★ 併購/整合 | 兩間公司各用 Kafka 與 RabbitMQ,短期內都不能換 |
| ② ★ 跨地域/跨叢集複製 | Kafka MirrorMaker 2、Confluent Cluster Linking、RabbitMQ Shovel/Federation |
| ③ ★ 遷移期間並行 | 從 RabbitMQ 遷到 Kafka,橋接讓兩邊同時有資料,可逐服務切換 |
| ④ 雲端/地端混合 | 地端 broker ↔ 雲端託管服務 |
★ 場景 ③ 是最常見也最有價值的用法:
橋接讓「換 broker」變成可以一個服務一個服務切換,而不是一次性大爆炸。
★★ 橋接必然遇到的四個語義落差
不同 broker 的保證不一樣,橋接不可能無損:
① ★★ 順序
RabbitMQ 的 queue(單一消費者)有序 → Kafka 需要分區鍵才有序
★ 橋接程式必須決定「用哪個欄位當 partition key」—— 選錯就沒有順序保證
② ★★ 投遞保證變成「至少一次」的疊加
來源 ack → 目標發送失敗 → 訊息丟了
目標發送成功 → 來源 ack 失敗 → ★ 重送 ⇒ 重複
★ 橋接本身就是一次雙寫問題,無法做到恰好一次
→ ★ 正確順序:先成功發到目標,再 ack 來源(寧可重複,不要遺失)
③ ★ 標頭與 metadata
AMQP 的 properties ↔ Kafka 的 headers ↔ SQS 的 message attributes
★ 型別與大小限制都不同,對應不完整就會靜默掉欄位
→ ★ correlation-id / trace-parent 一定要手動確保有帶過去
④ ★ 大小限制
來源允許 10 MB、目標上限 1 MB → ★ 橋接處才發現,而且無處可退
→ 要嘛前置用 [[寄物單]],要嘛橋接把超大訊息送進 [[無效訊息通道]]
★ Go 的橋接骨架
func bridge(ctx context.Context, src Source, dst Sink) error {
for {
msg, err := src.Fetch(ctx)
if err != nil { return fmt.Errorf("fetch: %w", err) }
out, err := translate(msg) // ★ 純函式,可測(見 [[訊息轉換器]])
if err != nil {
_ = dst.PublishTo(ctx, invalidChannel, msg, err)
_ = msg.Ack() // ★ 壞訊息要 ack 掉,否則堵住
continue
}
if err := dst.Publish(ctx, out); err != nil {
_ = msg.Nack(true) // ★ 目標失敗 → 不 ack,讓來源重送
continue
}
_ = msg.Ack() // ★★ 一定在目標成功「之後」
}
}★ 這段的三個關鍵順序:翻譯失敗 → 搬走並 ack;目標失敗 → 不 ack;成功 → 才 ack。
任一個順序寫反都會造成遺失或無限堵塞。
★★ 最重要的警告:橋接很容易變成永久的
「我們先用橋接,遷移完就拆掉」
→ 三年後橋接還在,而且:
★ 兩套 broker 都要維運、都要值班
★ 訊息路徑變成「A → 橋接 → B」,除錯要跨兩個系統追
★ 橋接是單點,掛了沒有任何錯誤出現(見 [[通道配接器]] 的同一個問題)
★ 沒人記得它為什麼存在
★ 對策:橋接上線時就設一個明確的退場條件與日期,寫進 ticket。
沒有退場計畫的橋接,就是永久增加一倍的維運面積。
★ 兄弟辨析
| 差別 | |
|---|---|
| 通道配接器 | ★ 連接「非訊息系統 ↔ 訊息系統」(DB、API、檔案) |
| 訊息匯流排 | 架構層級:一組共用通道 + 標準格式,★ 不是點對點的轉接 |
| 訊息轉換器 | 橋接內部用到它(格式轉換) |
| 標準資料模型 | ★ 橋接多了以後,就會有人提議用它——注意它的代價 |
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
-
橋接需為每對要連通的通道設定與維護,通道多時管理成本高。
-
與通道配接器不同:橋接連的是「兩套訊息系統」,配接器連的是「非訊息的系統」。
-
★★ 橋接本身就是雙寫問題,做不到恰好一次。 正確順序是「先成功發到目標,再 ack 來源」——寧可重複,不要遺失。
-
★★ 「遷移完就拆掉」的橋接通常會變成永久的。 上線時就要有明確的退場條件與日期。
-
★ 順序保證無法自動搬過去。RabbitMQ 的 queue 順序 → Kafka 需要選對 partition key。
-
★ 標頭對應不完整會靜默掉欄位。correlation-id/trace-parent 要手動確保帶過去。
-
★ 橋接是單點,掛了不會有任何錯誤出現。 要監控「最後一筆搬運的時間」與兩邊的 lag。
-
橋接讓除錯要跨兩個系統追。trace id 必須貫穿。
-
不要用橋接掩蓋「其實該統一 broker」。兩套 broker 的維運成本是加倍的。
🔗 相關工具
- 通道配接器 Channel Adapter(對照:接非訊息系統 vs 橋接兩套訊息系統)
- 訊息匯流排 Message Bus(橋接可作為打造跨系統匯流排的一環)
- 訊息通道 Message Channel(橋接連接兩邊的通道)
- 企業整合模式
- 通道配接器 —— 連接非訊息系統
- 訊息匯流排 —— 架構層級的共用通道
- 訊息轉換器 —— 橋接內部的格式轉換
- 寄物單 —— 大小限制的前置處理
- 無效訊息通道 —— 翻譯不了的訊息
- 保證投遞 —— 橋接的投遞保證疊加