脈絡:本章許多模式提供了「把訊息路由到正確目的地、而發起端不必知道最終目的地」的方式,各自聚焦於特定型別的路由邏輯。但它們合起來解決的是一個更大的問題。
整合義大利麵#
單純使用 Message Channel 已經在收發雙方之間提供了一層間接——寄件端只知道通道、不知道接收者。
但若每個接收者都有自己的通道,這層間接就沒什麼意義了:寄件端不必知道接收者的位址,卻得知道與該接收者關聯的正確通道名稱。
除了最簡單的方案以外,訊息方案都連接著多個應用程式。
若我們為「每個應用程式對每個其他應用程式」都建一條通道,系統中的通道數量會迅速爆炸成無法管理的規模,造成「整合義大利麵」。
這類架構往往是方案隨時間長出來的結果:先是客服系統得和會計系統對話;接著客服系統也得從庫存系統取資料;然後出貨系統得把運費更新到會計系統……「再加一塊就好」很容易就毀掉方案的整體完整性。
要求每個應用程式都明確地與其他每個應用程式溝通,會迅速拖垮系統的可維護性。例如客服系統裡的客戶地址一改,它就得送訊息給所有保有客戶地址副本的系統;而每次新增一個系統,客服系統都得知道那個系統用不用地址,並跟著修改。

圖 7-25:點對點連接造成的整合義大利麵
Publish-Subscribe 不夠#
Publish-Subscribe Channel 提供了某種基本路由——訊息被送給每個訂閱該通道的應用程式。這在簡單的「廣播」情境中管用,但路由規則往往複雜得多(例如進站訂單訊息可能要依規模或性質路由到不同系統)。
為了避免讓應用程式負責決定訊息的最終目的地,中介軟體應該包含能把訊息路由到適當目的地的 Message Router。
個別的路由模式已經幫我們把收發雙方解耦了。例如 Recipient List 能把「所有接收者的知識」從寄件端抽出來、放進中介軟體層。把邏輯搬進中介軟體層有兩個好處:
- 許多商業中介軟體與 EAI 套件提供了專為這類任務設計的工具與函式庫,簡化編碼工作——我們不必自己寫 Message Endpoint 相關的程式碼(例如 Event-Driven Consumer 或執行緒管理)。
- 在中介軟體層實作邏輯,能讓邏輯比在應用程式內部「更聰明」——例如使用動態 Recipient List,新系統加入整合方案時就不必改程式碼。
然而,擁有大量個別的 Message Router 元件,可能幾乎和我們原本想解決的整合義大利麵一樣難管理。
解法#
使用中央 Message Broker 有時被稱為輻輳(hub-and-spoke)架構風格。

圖 7-26:Message Broker 解法示意(輻輳架構)
它是架構模式,不是設計模式#
Message Broker 的尺度與本章其他模式略有不同——它是架構模式,而非個別的設計模式。就這一點而言,它可以與 Pipes and Filters 架構風格相提並論。
相對於 Pipes and Filters 只是把個別元件串起來形成更複雜的訊息流,Message Broker 關心的是更大的方案,幫我們應付管理這類系統時無可避免的複雜度。
Message Broker 不是一個單體元件。它內部使用本章介紹的許多路由模式——所以一旦你決定採用 Message Broker 作為架構模式,就可以挑選合適的 Message Router 設計模式來實作它。
中央化的雙面刃#
中央維護的優點也可能變成缺點:把所有訊息都路由過單一個 Message Broker,可能讓它變成嚴重的瓶頸。
有幾種技巧能緩解:
- 部署多個實例——Message Broker 模式只要求我們開發單一個執行路由的實體,並沒有規定部署時要跑幾個實例。
若 Message Broker 的設計是無狀態的(只由無狀態元件組成),就能輕鬆部署多個實例來提升吞吐量;而 Point-to-Point Channel 的性質確保任何進站訊息只被其中一個實例消費。
- 設計多個各司其職的 Broker——在許多複雜整合方案中,設計多個 Message Broker、各自專精方案的某一部分是合理的,這能避免造出複雜到無法維護的「über-Message Broker」。
但明顯的反面是:我們不再有單一維護點,可能製造出新形態的「Message Broker 義大利麵」。
- Message Broker 階層——一種很好的組合風格。
這種配置很像由多個子網組成的網路:若訊息只需在某個「子網」內的兩個應用程式之間傳遞,就由本地 Message Broker 管理路由;若目的地在另一個子網,本地 Broker 就把訊息交給中央 Message Broker 決定最終目的地。
中央 Broker 執行的功能與本地 Broker 相同,只是它解耦的不是個別應用程式,而是由多個應用程式組成的整個子系統。
別忘了轉換#
因為 Message Broker 的目的是降低應用程式之間的耦合,它通常還得處理應用程式之間的訊息資料格式轉換。
讓 Message Broker 抽象掉訊息路由,對送件應用程式並沒有幫助——如果它仍得用(本該被隱藏的)目的地訊息格式來組訊息的話。
許多情況下,Message Broker 內部使用 Canonical Data Model 來避免 N 平方問題——「在系統中每兩個接收者之間互相翻譯所需的轉譯器數量,會隨參與者數量的平方成長」。
範例:商業 EAI 工具
多數商業 EAI 工具提供的功能,能大幅簡化整合方案中 Message Broker 元件的建構。這些套件通常提供三類支援:
- 內建端點程式碼——多數 EAI 套件已包含把訊息送上/收自訊息匯流排的全部程式碼,開發者完全不必操心任何傳輸相關的程式碼。
- 視覺化設計工具——讓開發者用視覺元件(路由器、決策點、轉換器)組出 Message Broker 的功能。這些工具讓訊息流一目了然,並能把許多元件的編碼工作縮減到一行程式碼(例如一個求值函式或一條規則)。
- 執行期支援——多數 EAI 套件也提供成熟的執行期支援,涵蓋方案部署與監控流經 Message Broker 的流量。