消息總線目前為Java程式設計語言提供了SDK,同時針對其他語言提供了一個稱之為httpBridge的http代理。這基本可以滿足大部分主流程式設計語言對消息總線的使用需求,但這也僅僅是對技術層面上的需求的滿足。在業務層面上,尤其是面對老的業務系統的适配一直都是個難題,這篇文章談談面對一個線上上運作的業務系統,如何使得引入消息總線的總體成本盡可能得低。
就消息總線的兩種使用方式而言,無論是SDK的方式還是httpBridge的方式,都需要往第三方系統引入對消息總線的依賴,這些依賴包括但不僅限于:SDK(jar)本身的依賴、API調用接口的依賴以及了解、熟悉或學習的成本。我們說盡量将總體成本降到最低,其實這些依賴就是所謂的成本,當然還有維護的成本等(當你對原有系統引入新的技術元件,就必須接受引進新Bug的風險)。
上面談到了依賴,第三方對消息總線的依賴,我們想看看能否對這種現狀進行“依賴轉移”。這個思維的變換對程式員來說是比較容易過渡的,作為Java程式員重度依賴的架構——Spring,主要就是用來針對性得處理類似問題(當然在Spring裡稱之為Ioc即控制反轉)。
要想進行依賴轉移,我們首先需要清楚第三方為什麼會對消息總線産生依賴性?因為消息總線隻是個中間件。它不知道通信雙方的消息内容以及通信時機(生産、消費的時機,有可能會存在觸發條件)。是以第三方如果想通過消息總線跟其他元件通信,它們必須主動調用消息總線來生産消息或者消費消息。
通過上面的分析,我們知道第三方元件對消息總線的依賴性是因為它們必須主動跟消息總線互動。就消費而言,假設消費的時機沒那麼重要(隻要我關注的隊列裡有消息,我就可以消費掉),那麼我們是否可以讓消息總線主動把消息推送給我?
這裡有兩個在表達上很類似,其實差别很大的問題,必須首先澄清一下:
第三方接收消息總線主動推送的消息
第三方以推送的模型從消息總線上消費消息
第一個問題的主要想表達的意思是:第三方系統不主動與消息總線或其他任何元件連接配接,就能接收到消息;
第二個問題的主要想表達的意思是:通過消息總線消費消息的Push模型(另一個模型是pull),這隻是消費機制,這樣的機制建立在主動調用消息總線接口的前提下。
很明顯我們想要解決的是第一個問題。如何讓消息總線主動推送消息?如果你把容納消息的容器看做是資料源,那麼首先消息總線的隊列就是資料源,現在相當于要把一個資料源裡的資料寫入到另一個資料源,而這裡的“另一個資料源”以及“寫入”這一行為要能夠很輕易得跟第三方系統銜接。可行的一種方式是第三方系統單獨開發一個接收消息的http請求處理程式(考慮到大部分系統都是web系統,那麼這裡就是一個單獨的controller或者如果是Java
Web技術,那麼就是一個Servlet)。那麼“另一個資料源”直接就可以是第三方系統,而“寫入”
這一行為的技術是通過http這種平台無關的通信協定。
消息總線如何知曉第三方資料源的接口?這需要引入一個registry(系統資料庫),也就是說當第三方系統在申請隊列的時候,它可以往該系統資料庫内登記一條資訊以表明:如果該隊列接收到消息,請代為轉發到我注冊的這個接口。是以,它其實是個key-value形式的映射關系的容器來銜接消息總線(隊列)以及第三方系統(接口),這成功得進行了依賴轉移!
有了這個對應關系,我們就可以給消息總線開一個專門掃描該系統資料庫的cron job,我們暫且将其稱之為:consume proxy
service。該Job以一定的時間間隔掃描該registry裡的所有隊列-接收接口的映射關系,然後以pull的模式嘗試從相應的隊列裡消費消息,當消費到消息之後,将其發送到已被注冊的接口,而該接口是第三方一個專門用于接收消息總線消息的請求處理器,大緻流程如下:

見圖中所有虛線部分。
現在第三方系統隻需知道消息總線的消息格式即可,而無需直接對消息總線産生較強的依賴——因為它不再需要主動跟消息總線通信,而是被動接收。
其實依賴對哪一方都會産生影響,這也是軟體開發中一直在強調“低耦合”的原因。一旦消息總線“依賴”第三方系統——因為它要将消息通過http請求發送個第三方系統。http請求的特征:請求響應模型,如果第三方系統不給響應,或者惡意hold住請求不釋放,那麼消息總線的這個代理消費并轉發服務很容易被拖死。
解決這個問題可以有如下的一些手段:
給第三方接口建議:如果處理消息的邏輯很耗時,可以暫時将消息緩存後進行異步處理,先讓請求傳回
對第三方接口進行嚴格的稽核:對可通路性以及請求的響應速度給出嚴格的稽核标準
消息總線提供的轉發服務被實作為“盡力而為”的服務:何為盡力而為?也即非核心服務,它的穩定狀态不會影響消息總線提供的核心服務。并且它應該被設計為“可降級”的。當發現它嚴重不穩定時,可将其關閉(因為消息如果沒被轉發出去,它仍然被存儲在隊列中,并不會丢失,後續仍可消費)。甚至可以将整個虛線部分轉移到消息總線的外部實作。
可以開發一些“watch dog”服務,專門監控第三方接口,一旦發現異常,即将其從registry中移除
以上手段可以多條并用來保障代理消費&轉發服務的穩定性。
上面我們主要談到了對消費方而言,通過依賴轉移的方式來使得第三方系統對消息總線的依賴降到最低,進而減少了第三方系統對消息總線的接入成本、維護成本以及引入的複雜性。其實能夠做到這一點主要是因為我們假設了:消費方對消費的時機沒有要求,隊列裡有資料就可以被消費走。是以這種依賴轉移的方式,無法被應用在想要生産消息的系統中。是以生産者對消息總線的依賴無法降低!
消費者對消息總線依賴性降低的好處主要展現在需要應用Pub/Sub模型的系統群中。在這個系統群中,消息的生産者所對應的業務系統較少,而消息的消費者對應的業務系統較多。這種降低依賴性手段還有一個前提:第三方系統都是web系統。
這種消費模式即可視為消息總線的主動推送模式。隻是一個設想,目前還沒有正式實作,如果消息總線提供這個功能,那麼它将在“消費模式”以及“消費消息的接口”(API)上同時提供“推拉結合”的方式。
原文釋出時間為:2015-05-14
本文作者:vinoYang