1. 程式人生 > >訊息中介軟體剖析

訊息中介軟體剖析

本文首先從概念和應用場景對訊息中介軟體做總體描述,然後對幾種典型的訊息中介軟體從原理到實現進行分析和闡述,並進一步詳細介紹了基於JMS規範的訊息中介軟體。

什麼是訊息中介軟體

訊息中介軟體是一套系統(或平臺),用於應用程式之間進行通訊,系統通過訊息傳遞完成互動。

訊息中介軟體的主要特點有以下幾個。

1. 分散式:訊息中介軟體都是分散式的,因此才可以提供非同步、解耦等功能。

2. 可靠性:基於訊息的通訊是可靠的,訊息不會丟失。大多數訊息中介軟體都提供將訊息持久化到磁碟的功能。

3. 非同步:通過訊息中介軟體,可將遠端同步呼叫拆解成為非同步呼叫。對於不需要獲取遠端呼叫結果的應用場景來說,效能提升明顯。

4. 鬆耦合:訊息直接由中介軟體儲存和分發。訊息生產者只需關注如何將訊息傳送給訊息中介伺服器;消費者只需關注如何從中介伺服器訂閱。生產者和消費者之間是完全解耦的,不需要知道彼此的存在。

5. 事件驅動:可以將複雜的應用系統重構成為事件驅動的系統。事件溯源(Event Sourcing),表示一個物件從建立到消亡,會經過的多種狀態。如果把物件的狀態變化都儲存下來,不但可以根據狀態變化記錄獲取物件的當前狀態,也可以回溯物件的變化過程。訊息中介軟體能很好地支援這樣的系統設計方式,將觸發物件狀態變化的事件放入訊息佇列。

在帶來好處的同時,引入訊息中介軟體也有一些需要注意的地方。

1. 分散式帶來的複雜性:訊息中介軟體都是分散式的,引入分散式會大大增加系統複雜度,在不同主機、不同程序之間的呼叫和除錯,會帶來更多的不穩定性。分散式系統還會增加對外部系統的依賴。即使自己的系統沒有問題,也可能會因為依賴系統出問題而導致系統不穩定。因此,Martin Fowler曾說:“分散式呼叫的第一原則就是不要分散式。”

2. 同步呼叫應該考慮其他方式:儘管訊息中介軟體也可用於同步呼叫,但這並不是它的長項,同步呼叫可以考慮使用HTTP、NIO等其他方式。

圖1描述了訊息中介軟體的組成部分。

3. 訊息中介(Broker):可理解為訊息中介軟體的伺服器。訊息中介用於儲存訊息,並且維護訊息消費者和訊息佇列之間的訂閱關係(也可由消費者自己維護)。

訊息在中介如何儲存,是決定訊息中介軟體功能和效能的最重要因素。目前來說,最主要的兩種儲存訊息的方式是kv儲存和順序儲存。後文將詳細介紹兩種不同儲存引擎訊息中介軟體的區別。

圖1  訊息中介軟體的組成部分

1. 訊息生產者(Producer):與訊息消費者一起組成訊息中介軟體的客戶端。生產者用於傳送訊息到訊息中介。

客戶端連線伺服器一般可以選擇TCP、HTTP等協議。內網基於長連線的TCP協議效率更高,公網可以考慮HTTP協議穿透防火牆。

2. 訊息消費者(Consumer):與訊息生產者一起組成訊息中介軟體的客戶端。消費者用於從訊息中介獲得訊息並交給業務系統使用。

訊息的消費分成推送和拉取兩種模式。推送是訊息中介主動將訊息傳送給訊息消費者,拉取則是訊息消費者主動從訊息中介獲取訊息。兩種模式的使用場景不太一樣,各有優缺點,下文也會詳細介紹。

為了便於理解,在這裡將訊息中介軟體和關係型資料庫做一個比較:1. 訊息中介相當於資料庫的伺服器;2. 訊息生產者相當於使用INSERT語句的SQL客戶端;3. 訊息消費者相當於使用SELECT語句的SQL客戶端。

當然這個比較不是非常恰當。例如根據實現方式不同,訊息的刪除可能由消費者發起,也可能由訊息中介主動發起。但能比較直觀說明,訊息中介軟體是由伺服器和客戶端組成,以及它們所承擔的職責。

JMS

JMS的全稱是Java Message Service,即Java訊息服務,定義了Java平臺訊息中介軟體的技術規範。JMS只提供了應用程式對訊息中介軟體操作的介面規範,並未提供實現,其實現由各個訊息中介軟體廠商的驅動程式來提供,和Java的另一個規範標準JDBC相似。遵循JMS規範的訊息中介軟體都使用統一的API。

JMS定義了訊息的程式設計模型,如連線工廠、會話、訊息目的地、訊息生產者、訊息消費者、訊息體、訊息優先順序和訊息型別等。本文並不會詳細介紹JMS,有興趣瞭解請查閱相關資料。但會重點介紹JMS中定義的訊息型別,因為後面介紹的幾種訊息中介軟體如何支援訊息型別是本文的關鍵之一。

訊息型別分為點對點和釋出/訂閱兩種。

1. 點對點(Point To Point):訊息生產者將訊息傳送到訊息佇列(Queue)中,只有一個消費者能夠消費此訊息,消費完成之後訊息即刪除。

這裡應該注意的是,任意一個消費者都可以消費這個訊息,但訊息絕對不會被兩個消費者重複消費。

訊息的消費者和生產者沒有時間依賴,可以先發送訊息,再啟動消費者。

圖2展示了JMS的點對點訊息型別。

圖2   點對點訊息型別

2. 釋出/訂閱(Publish/Subscribe):訊息生產者將訊息傳送到訊息主題(Topic)中,所有訂閱這個主題的消費者都可以消費此訊息,當所有訂閱者都消費完成之後才能刪除訊息。

訊息的生產者和消費者之間有時間依賴,只有事先訂閱這個主題的消費者才可消費。如果先發送訊息,後訂閱主題,那麼訂閱之前的訊息將不能被這個訂閱者消費。

訂閱者又可分為持久化訂閱和非持久化訂閱。如果持久化的訂閱者在訂閱之後離線,收到的訊息仍會在訂閱者再次上線時收到,不會錯過訊息。而非持久化的訂閱者一旦離線,離線時的訊息將被錯過。

圖3展示了JMS的釋出/訂閱訊息型別。

圖3   釋出/訂閱訊息型別

最後,需要介紹訊息傳遞語義(Message Delivery Semantics)。訊息傳遞的擔保有3種級別:最多一次(At Most Once),至少一次(At Least Once)和精確地僅傳送一次(Exactly Once)。

【最多一次】

訊息只發送或消費一次,無論訊息中介是否收到訊息,或者訊息是否已消費成功,都不會再次傳送。

這樣做的問題是,訊息可能會丟失。雖然客戶端傳送了訊息,但訊息中介還來不及儲存就崩潰,那麼這條訊息就會丟失。

【至少一次】

如果訊息中介沒有明確告訴客戶端訊息已經收到,那麼客戶端會重新發送或消費這條訊息。

這樣做的問題是,訊息可能會重複傳送或消費。例如訊息已經存到了訊息中介,但還沒來得及給客戶端傳送確認資訊,訊息中介就崩潰了。那麼等訊息中介重新啟動之後,客戶端會重新發送這條訊息,造成重複。

【精確地僅傳送一次】

既不會多也不會少傳送訊息。一般通過事務來實現,只有訊息中介收到客戶端確認處理成功的資訊,才會提交事務,否則在經過一定時間限制之後訊息會回滾。精確地僅傳送一次訊息,不會丟失也不會有重複的訊息,但要達到這一點,對效能的損耗非常大。

JMS要求訊息精確地僅傳送一次。

圖4   解耦訂單系統

應用場景

【業務解耦】

各個業務系統僅需要處理自己的業務邏輯,並且傳送事件訊息到訊息中介軟體。下游業務系統直接訂閱訊息中介軟體的佇列或主題獲取事件。這樣不但解耦了系統間的依賴,而且使呼叫非同步化,提升了系統的效能。圖4顯示瞭如何通過訊息中介軟體將訂單系統解耦。

【削峰填谷】

如果上游系統的吞吐能力強於下游系統,那麼在上游系統滿負荷時將沖垮下游系統。使用訊息中介軟體的定時定量推送或者定時定量拉取,可在上游峰值時堆積訊息,在峰值過去時慢慢消費,增強系統的緩衝能力。圖5顯示瞭如何通過訊息中介軟體緩衝業務洪峰,並且使用定時定量分流消費訊息。

圖5   峰值緩衝和定量消費

【廣播通知】

系統一個狀態的改變,需要通知多個相關係統,可通過訊息訂閱的方式推送給各個訂閱者系統。比如資料庫值的改變,需要通知所有的快取系統更新,可以把資料庫值改變傳送訊息給訊息中介軟體,然後各快取訂閱相關主題,收到訊息後更新自己的快取。圖6顯示了資料中心如何通過廣播通知已訂閱的快取系統更新資料。

圖6    資料中心廣播通知已訂閱的快取系統

【日誌分析】

日誌分析往往需要處理大量日誌,不可能儲存在一臺物理機上。訊息中介軟體可提供一個叢集,用來儲存海量訊息,將其快取到訊息中介軟體。比較常用的日誌分析系統是使用日誌收集元件(如Flume)收集,儲存到高吞吐量的訊息中介軟體(如Kafka),供實時分析系統(如Storm)分析日誌。圖7描述了日誌分析系統的基本組成部分。

圖7   日誌分析系統

訊息中介軟體概覽

表1展示了目前比較流行的訊息中介軟體的簡單對比,希望對讀者的選型有所幫助。

表1  流行的訊息中介軟體對比

通過上面的分析可知,處理核心業務邏輯的場景和處理海量分析的場景是截然不同的。因而,訊息中介軟體也天然分成了兩大流派——高可靠和高吞吐。下期將對這部分內容進行詳細介紹。

作者:張亮

作者簡介:噹噹網架構師,噹噹技術委員會成員。對架構設計、訊息中介軟體、分散式通訊等方面興趣濃厚。