消息中間件

轉載地址:http://ink.csdn.net/articles/show/55f27505c384fe3b0e202526


消息中間件剖析

本文首先從概念和應用場景對消息中間件做總體描述,然後對幾種典型的消息中間件從原理到實現進行分析和闡述,並進一步詳細介紹了基於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  流行的消息中間件對比

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章