兩個應用程式想交換資料時,會把資料送過連接兩者的通道。送資料的一方未必知道誰會收到,但只要挑對了通道,寄件端就知道接收者會是「在那個通道上找這類資料」的人。生產共享資料的應用程式,就這樣有了與想消費它的應用程式溝通的管道。

幾個貫穿本章的主題#

決定「要用 Message Channel」是簡單的部分——應用程式有資料要送或要收,就得用通道。真正的挑戰在於:你的應用程式需要哪些通道、各自拿來做什麼。

通道集合是固定的#

應用程式可用的通道集合傾向是靜態的。設計應用程式時,開發者必須知道該把哪種資料放到哪裡才能與別人共享,也必須知道該去哪裡找來自別人的哪種資料。

這些通訊路徑不能在執行期動態建立與發現,必須在設計期就談好,應用程式才知道資料從哪來、往哪去。

例外:確實存在動態通道的情況

雖然多數通道必須靜態定義,仍有兩個實用的例外:

  • Request-Reply 的回覆通道——請求方可以建立或取得一個回覆方毫不知情的新通道,把它當作請求訊息的 Return Address,回覆方就能使用它。
  • 支援階層式通道的訊息系統——接收端訂閱階層中的某個父通道,寄件端就能發布到一個接收端毫不知情的新子通道,訂閱者仍然收得到訊息。

除了這些相對罕見的情況,通道通常在部署期定義,應用程式則圍繞一組已知的通道來設計。

誰決定有哪些通道#

是訊息系統定義好通道、要求應用程式將就,還是應用程式決定需要什麼、要求訊息系統提供?

沒有簡單答案——設計通道集合是個反覆迭代的過程。最初由應用程式決定訊息系統得提供哪些通道;後來的應用程式會試著圍繞既有通道設計自己的通訊,行不通時才要求新增通道。當一組應用程式已經在用某組通道、而新應用程式想加入時,它們也會沿用既有通道;而既有應用程式新增功能時,則可能需要新通道。

通道是單向的#

通道到底是單向還是雙向?嚴格說來兩者皆非——它比較像一個「有些應用程式往裡加資料、有些從中取資料」的桶子(只是這個桶子以某種協調方式分散在多台電腦上)。

但因為資料裝在訊息裡、從一個應用程式流向另一個,這就給了通道方向性,使它成為單向的。

若通道是雙向的,就意味著同一個應用程式既往這個通道送訊息、又從它收訊息——技術上做得到,但幾乎沒有意義,因為該應用程式會不斷消費掉自己本來要送給別人的訊息

因此就實務而言通道都是單向的。結果是:兩個應用程式要雙向對話,就需要兩個通道,一個方向一條(見下一章的 Request-Reply)。

使用通道時要做的決策#

  • 一對一還是一對多——想把資料只給某一個應用程式,用 Point-to-Point Channel。這不保證該通道上每筆資料都送到同一個接收者(通道可以有多個接收者),但保證任何一筆資料只會被其中一個應用程式收到。若希望所有接收端都收得到,就用 Publish-Subscribe Channel——這種通道實際上會為每個接收者複製一份資料。
  • 什麼型別的資料——電腦記憶體中的任何資料都得符合某種型別:一種已知的格式或預期的結構,帶有約定好的意義;否則資料就只是一堆位元組,無從理解。訊息傳遞也一樣,Datatype Channel 的原則就是「同一個通道上的所有資料必須是同一型別」。

這正是訊息系統需要大量通道的主因:若資料可以是任何型別,任兩個應用程式之間每個方向只需要一個通道就夠了。

  • 無效訊息與死信——訊息系統能確保訊息被正確遞送,卻無法保證接收端知道拿它怎麼辦。接收端對資料的型別與意義有所預期,收到不符預期的訊息時能做的不多——但它可以把這則怪訊息放到專門的 Invalid Message Channel,期待某個監控該通道的工具撿走並想辦法處理。許多訊息系統也有類似的內建機制 Dead Letter Channel,收容「成功送出、最終卻無法成功遞送」的訊息。
  • 抗當機——訊息系統若崩潰或因維護而關閉,訊息會怎樣?重新上線後訊息還在通道裡嗎?預設不會——通道把訊息存在記憶體中。Guaranteed Delivery 讓通道持久化,把訊息存到磁碟;這犧牲效能,但即使訊息系統本身不可靠,訊息傳遞仍然可靠。
  • 非訊息客戶端——應用程式若無法連上訊息系統,卻仍想參與訊息傳遞怎麼辦?一般就沒轍了;但只要訊息系統能以某種方式連上該應用程式——透過它的使用者介面、業務服務 API、資料庫,或 TCP/IP、HTTP 這類網路連線——就能用訊息系統這一側的 Channel Adapter 把通道接上應用程式,既不必改動應用程式,也未必需要在同一台機器上跑訊息客戶端。有時那個「非訊息客戶端」其實真的是訊息客戶端,只是屬於另一套訊息系統;此時一個同時是兩套系統客戶端的應用程式,可以在兩者之間搭起 Messaging Bridge,實際上把它們接成一套複合的訊息系統。
  • 通訊骨幹——當愈來愈多企業應用連上訊息系統、把功能透過訊息開放出來,訊息系統就成了企業功能的一站式集中點:新應用程式只需知道用哪些通道請求功能、監聽哪些通道取得結果。訊息系統本身於是成為 Message Bus——一條通往企業各種且不斷變動的應用程式與功能的骨幹。

這種整合上的理想境界,從一開始就刻意為它而設計,會更快也更容易達成。

小結#

讓應用程式用上訊息傳遞,不只是把它們接上訊息系統就好——訊息得有通道可傳;而隨便丟幾條通道也不成事。

通道必須帶著目的去設計,依據的是被共享的資料型別、提供資料的應用程式類型,以及接收資料的應用程式類型。本章要說明的,就是設計這些通道時要做的各種決策。

為了說明模式,本章每個模式都配有一個虛構、簡化的「股票交易」情境範例。這些範例都不該用來當作真實交易系統的實作基礎,但它們能快速而具體地展示模式怎麼用。