脈絡:企業裡有數套既有系統,它們必須能共享資料,並對一組共同的業務請求以統一的方式運作。
保險公司的例子#
企業裡常有一堆各自獨立運作、卻必須協同運作的應用程式。EAI 描述了對這個問題的解答,卻沒說怎麼做到。
以一家販售多種保險商品(壽險、健康險、車險、房屋險)的保險公司為例。歷經企業併購與 IT 開發風向的變遷,這家企業擁有數套各自管理不同商品的獨立應用程式。
一位業務員想賣給客戶好幾種不同保單,就得替每一種保單分別登入一套系統——既浪費力氣又增加出錯機會。
需求是:
- 業務員需要一個單一、統一的應用程式來銷售整組保單。
- 其他角色(理賠人員、客服人員)也需要各自的應用程式,但同樣希望呈現統一的視圖。
- 各商品應用程式之間必須能協同——例如客戶買多張保單時提供折扣,或處理一筆涵蓋多張保單的理賠。
幾條走不通的路#
- 重寫所有商品應用程式,讓它們用同一套技術並能協作——替換那些「已經能動(只是不能一起動)」的系統,時間與金錢成本高得無法承受。
- 為業務員做一個統一的應用程式——但這個應用程式必須連上真正管理保單的那些系統。這樣不但沒有統一系統,反而多造出一個無法與其他系統整合的系統。
- 讓業務員應用程式直接整合所有其他系統——這會讓它複雜得多,而且這份複雜度還會在理賠人員與客服人員的應用程式中重複一遍;更糟的是,這些統一的使用者應用程式完全幫不上商品應用程式彼此整合。
就算真讓這些應用程式協作起來了,企業組態的任何一點變動都可能讓一切停擺。不是所有應用程式隨時都在線上,而正在跑的那些必須能在其他系統停擺時受最小影響地繼續運作;隨著時間推移,應用程式還會不斷被加入與移除。
我們需要的,是一種讓商品應用程式以鬆散耦合方式協調、也讓使用者應用程式能與它們整合的整合架構。
解法#
Message Bus 是共同資料模型 + 共同命令集 + 訊息基礎設施的組合,讓不同系統透過一組共享介面溝通。
這類比於電腦系統中的通訊匯流排——它是 CPU、主記憶體與周邊裝置之間通訊的焦點。就像硬體類比一樣,訊息匯流排也由幾塊拼起來。
共同的通訊基礎設施#
就像 PCI 匯流排的實體針腳與線路為 PC 提供了共同、眾所周知的實體基礎設施,訊息匯流排也需要同樣角色的基礎設施。通常會選一套訊息系統來擔任這個實體通訊基礎設施,作為應用程式之間跨平台、跨語言的通用配接器。
- 基礎設施可能包含 Message Router 能力,以協助訊息正確地在系統之間路由。
- 另一個常見選項是用 Publish-Subscribe Channel 把訊息送給所有接收者。
配接器#
各系統必須設法與匯流排介接。最常見的作法是用商業或自製的 Channel Adapter 與 Service Activator——它們能處理諸如「用正確參數喚起 CICS 交易」,或「把匯流排上流動的通用資料結構,以各系統內部特有的方式呈現」這類事情。
這也要求一套所有系統都同意的 Canonical Data Model。
共同的命令結構#
就像 PC 架構有一組共同命令來表示實體匯流排上的各種操作(從某位址讀取位元組、寫入位元組),Message Bus 的所有參與者之間也需要一組大家都懂的共同命令。
- Command Message 說明了這項特性如何運作。
- 另一種常見實作是 Datatype Channel,由 Message Router 明確決定如何把特定訊息(例如採購單)路由到特定端點。
類比到這裡就失效了——匯流排上承載的訊息,粒度遠比實體匯流排上那種「讀/寫」訊息細緻得多。
帶來的效果#
在保險公司的例子中,Message Bus 既是各保險系統之間的通用連接器,也是想連上這些系統的客戶端應用程式的通用介面。
於是我們會有兩個 GUI,它們只認識 Message Bus——對底層系統的複雜性與怪癖一無所知。由匯流排負責把 Command Message 路由到正確的底層系統:
- 有些情況下,最好的處理方式是替該系統建一個配接器,由它解讀命令,再以該系統懂的方式與之溝通(例如喚起 CICS 交易或呼叫 C++ API)。
- 其他情況下,也許能把命令處理邏輯直接建進既有系統,作為喚起現有邏輯的另一種途徑。
Message Bus 一旦為業務員 GUI 做好,就很容易被其他 GUI 重用——理賠處理人員、客服人員,甚至讓客戶自行瀏覽帳戶的網頁介面。這些 GUI 的功能與權限控制各不相同,但它們與後端應用程式協作的需求是一樣的。
Message Bus 就是一種簡單的 SOA#
Message Bus 為企業構成了一套簡單而有用的服務導向架構:每個服務至少有一個接受約定格式請求的請求通道,通常還有一個支援指定回覆格式的對應回覆通道。 任何參與其中的應用程式都能透過發出請求、等待回覆來使用這些服務——那些請求通道實際上就扮演了可用服務的目錄。
前提條件#
- Message Bus 要求所有使用它的應用程式採用同一套 Canonical Data Model。
- 把訊息放上匯流排的應用程式,可能需要依賴 Message Router 把訊息導向適當的最終目的地。
- 不是為介接訊息系統而設計的應用程式,可能需要 Channel Adapter 與 Service Activator。
範例:股票交易
股票交易系統可能想提供一整套統一的服務:股票交易、債券拍賣、報價、投資組合管理等等。這可能需要數套必須彼此協調的後端系統。
一個較差的作法:為了替前端客戶 GUI 統一這些服務,系統可以用一個中介應用程式提供所有服務,並把執行工作委派給後端系統,後端系統之間甚至也透過這個中介協調。
但這個中介應用程式很容易變成瓶頸與單一故障點。
較好的作法:改用 Message Bus,為請求各項服務與取得回應提供通道。這條匯流排也能讓後端系統彼此協調;前端系統只需連上匯流排就能喚起服務。而且匯流排相對容易分散到多台電腦上,以提供負載分散與容錯。
匯流排就位之後:
- 接前端 GUI 變得相對容易——它們只需在正確的通道上收送訊息。一個 GUI 讓零售經紀人管理客戶的投資組合;另一個網頁 GUI 讓任何有瀏覽器的客戶自行管理投資組合;還有非 GUI 的前端可以支援 Quicken、Microsoft Money 這類個人理財軟體,讓客戶下載交易紀錄與當前價格。
- 抽換後端也變得容易——把一套交易應用換成另一套,或把報價請求分散到多個應用程式,都只是在 Message Bus 上加入與移除應用程式而已。新應用程式就位後,其他應用程式一概不必修改,照舊在匯流排的通道上收送訊息。