訊息佇列作為系統解耦,流量控制的利器,是分散式系統核心元件之一。
了解訊息佇列背後的實現是非常重要的。
今天,我們就一起來探討設計一個訊息佇列背後的技術。
訊息佇列整體設計思路主要是設計一個整體的訊息被消費的資料流。
這裡會涉及到:訊息生產Producer、Broker(訊息服務端)、訊息消費者Consumer。
1.Producer(訊息生產者):傳送訊息到Broker。
2.Broker(服務端):Broker這個概念主要來自於Apache的ActiveMQ,特指訊息佇列的服務端。
主要功能就是:把訊息從傳送端傳送到接收端,這裡會涉及到訊息的儲存、訊息通訊機制等。
3.Consumer(訊息消費者):從訊息佇列接收訊息,consumer回覆消費確認。
Broker(訊息佇列服務端)設計重點1)訊息的轉儲:在更合適的時間點投遞,或者通過一系列手段輔助訊息最終能送達消費機。
2)規範一種正規化和通用的模式,以滿足解耦、最終一致性、錯峰等需求。
總結起來就是兩次RPC加一次轉儲,如果要做消費確認,則是三次RPC。
為了實現上述訊息佇列的基礎功能:
1)訊息的傳輸
2)儲存
3)消費
就需要涉及到如下三個方面的設計:
1)通訊協議
2)儲存選擇
3)消費關係維護
通訊協議
訊息Message: 既是資訊的載體,訊息傳送者需要知道如何構造訊息,訊息接收者需要知道如何解析訊息,它們需要按照一種統一的格式描述訊息,這種統一的格式稱之為訊息協議。
傳統的通訊協議標準有XMPP和AMQP協議等,現在更多的訊息佇列從效能的角度出發使用自己設計實現的通訊協議。
1.JMS
JMS(Java MessageService)實際上是指JMS API。JMS是由Sun公司早期提出的訊息標準,旨在為java應用提供統一的訊息操作,包括建立訊息、傳送訊息、接收訊息等。
JMS通常包含如下一些角色:
JMS提供了兩種訊息模型:
1)點對點
2)以及publish-subscribe(釋出訂閱)模型。
當採用點對點模型時,訊息將傳送到一個佇列,該佇列的訊息只能被一個消費者消費。
而採用釋出訂閱模型時,訊息可以被多個消費者消費。
在釋出訂閱模型中,生產者和消費者完全獨立,不需要感知對方的存在。
2.AMQP
AMQP是 Advanced Message Queuing Protocol,即高階訊息佇列協議。
AMQP不是一個具體的訊息佇列實現,而 是一個標準化的訊息中介軟體協議。
目標是讓不同語言,不同系統的應用互相通訊,並提供一個簡單統一的模型和程式設計介面。 目前主流的ActiveMQ和RabbitMQ都支援AMQP協議。
AMQP是一種協議,更準確的說是一種binary wire-level protocol(連結協議)。這是其和JMS的本質差別,AMQP不從API層進行限定,而是直接定義網路交換的資料格式。
JMS和AMQP比較
JMS: 只允許基於JAVA實現的訊息平臺的之間進行通訊
AMQP: AMQP允許多種技術同時進行協議通訊
3.Kafka的通訊協議
Kafka的Producer、Broker和Consumer之間採用的是一套自行設計的基於TCP層的協議。Kafka的這套協議完全是為了Kafka自身的業務需求而定製的。
儲存選型對於分散式系統,儲存的選擇有以下幾種
1.記憶體
2.本地檔案系統
3.分散式檔案系統
4.nosql
5.DB
從速度上記憶體顯然是最快的,對於允許訊息丟失,訊息堆積能力要求不高的場景(例如日誌),記憶體會是比較好的選擇。
DB則是最簡單的實現可靠儲存的方案,很適合用在可靠性要求很高,最終一致性的場景(例如交易訊息),對於不需要100%保證資料完整性的場景,要求效能和訊息堆積的場景,hbase也是一個很好的選擇。
理論上,從速度來看,檔案系統>分散式KV(持久化)>分散式檔案系統>資料庫,而可靠性卻截然相反。
還是要從支援的業務場景出發作出最合理的選擇,如果你們的訊息佇列是用來支援支付/交易等對可靠性要求非常高,但對效能和量的要求沒有這麼高,而且沒有時間精力專門做檔案儲存系統的研究,DB是最好的選擇。
對於不需要100%保證資料完整性的場景,要求效能和訊息堆積的場景,hbase也是一個很好的選擇,典型的比如 kafka的訊息落地可以使用hadoop。
消費關係處理現在我們的訊息佇列初步具備了轉儲訊息的能力。
下面一個重要的事情就是解析傳送接收關係,進行正確的訊息投遞了。
市面上的訊息佇列定義了一堆讓人暈頭轉向的名詞,如JMS 規範中的Topic/Queue,Kafka裡面的Topic/Partition/ConsumerGroup,RabbitMQ裡面的Exchange等等。
拋開現象看本質,無外乎是單播與廣播的區別。
所謂單播,就是點到點;而廣播,是一點對多點。
為了實現廣播功能,我們必須要維護消費關係,通常訊息佇列本身不維護消費訂閱關係,可以利用zookeeper等成熟的系統維護消費關係,在消費關係發生變化時下發通知。
訊息佇列需要支援高階特性
訊息的順序投遞可靠性保證訊息持久化支援不同訊息模型多例項叢集功能事務特性等除了上述的訊息佇列基本功能以外,訊息佇列在某些特殊的場景還需要支援事務,訊息重試等功能。
以上,是從0到1設計一個MQ訊息佇列的經驗分享。