我們在使用不同的訊息佇列產品時,會遇到不同的“名詞”,今天我們今天來聊一些相關內容,包括佇列、主題、磁區等,
訊息佇列進化史
好的架構不是設計出來的,而是不斷演進得來的,訊息佇列的發展歷史,也印證了這一點,訊息佇列的訊息模型主要包括兩類:
- 佇列模型
- 發布-訂閱模型
佇列模型
最初的訊息佇列就是一個嚴格意義上的佇列,它是一個先進先出(FIFO)的線性表,在具體實作時可以采用鏈表或者陣列的形式,佇列只允許在后端進行插入操作,在前端進行洗掉操作,
早期的訊息佇列就是按照”佇列“的資料結構進行設計,其中生產者(Producer)發訊息就是入隊操作,消費者(Consumer)收訊息就是出隊操作,
如果有多個生產者向同一個佇列里面發送訊息,這個佇列中可以消費到的訊息,就是這些生產者生產的所有訊息的合集,訊息的順序就是按照這些生產者發送訊息的自然順序,如果有多個消費者接收同一個佇列的訊息,這些消費者之間是競爭的關系,每個消費者只能收到佇列中的一部分訊息,即任何一條訊息只能被其中的一個消費者收到,
如果需要將一份訊息發送到多個消費者,要求每個消費者都要收到全量訊息,這時單個佇列就不能滿足需求,可以考慮針對每個消費者都建一個單獨的佇列,讓生產者發送多份,但是這樣做,就違背了訊息佇列實作“服務解耦”的初衷,
發布-訂閱模型
發布-訂閱模型就是為了解決佇列模型中遇到的多個消費者都消費全量資訊的問題,
在發布-訂閱模型中,
- 訊息的發送方稱作發布者
- 訊息的接收方稱作訂閱者
- 服務端存放訊息的容器稱為主題
發布者將訊息發布到主題中,訂閱者在接收訊息之前需要先“訂閱主題”,
分布-訂閱模型和佇列模型相比,生產者就是發布者,消費者就是訂閱者,佇列就是主題,并沒有本質的區別,它們最大的區別在于,一份訊息資料能不能被消費多次的問題,
在發布-訂閱模型中,如果只有一個訂閱者,那它和佇列模型就基本一致了,即發布-訂閱模型在功能層面上是可以兼容佇列模型的,
常見訊息佇列產品的設計模型
接下來我們看常用的訊息佇列產品的佇列模型設計,
RabbitMQ
RabbitMQ是少數來在堅持使用佇列模型的產品之一,對于多個消費者的問題,它提供了Exchange模塊,位于生產者和消費者之間,生產者不關心將訊息發給哪個佇列,而是將訊息發給Exchange,由Exchange上配置的策略來決定將訊息佇列發送到哪個佇列中,
同一份訊息如果需要被多個消費者來消費,需要配置Exchange將訊息發送到多個佇列,每個佇列中都存放一份完整的訊息資料,可以為一個消費者提供消費服務,
RocketMQ
RocketMQ使用的訊息模型是標準的發布-訂閱模型,
幾乎所有的訊息佇列都使用一種“請求-確認”機制,確保訊息不會在傳遞程序中由于網路或者服務器故障而丟失,具體做法:
- 在生產端,生產者先將訊息發送給服務器,服務器在收到訊息并將其放入到主題或者佇列后,給生產者發送確認的回應,
- 在消費端,消費者在收到訊息并完成自己的業務邏輯后,給服務端發送訊息消費成功的確認,
這個機制保證了訊息在傳遞程序中的可靠性,但是引入這個機制后,為了確保訊息的有序消費,在某一條訊息被成功消費之前,下一條訊息是不能被消費的,即每個主題在任意時刻,至多只能有一個消費者在消費,這也就沒有辦法水平擴展消費者的數量來提升消費端整體性能,
為了解決這個問題,RocketMQ引入了佇列的概念,在每個主題中包含多個佇列,通過多個佇列來實作多實體并行消費訊息,RocketMQ只保證訊息在佇列上是有序消費的,在主題層面是無法保證的,
RocketMQ的訂閱者是通過消費組來體現的,每個消費組都消費主題中的一份完整的訊息,不同消費組之間的消費進度是相互隔離的,即一條訊息被消費組1消費后,還會被消費組2消費,
消費組中有多個消費者,同一個組內的消費者是競爭的關系,每個消費者負責消費組內的一部分訊息,如果一條訊息被消費者1消費,那么同一個消費組內的其他消費者沒有辦法再次消費這條訊息,
為了維護多個消費組的不同的訊息消費進度,RocketMQ會為每個消費組在每個佇列上都維護一個消費位置資訊,即Offset,這個位置之前的訊息都已經被消費,之后的訊息都沒有被消費,沒成功消費一條訊息,消費位置加一,
Kafka
Kafka也是采取發布-訂閱模型,
Kafka和RocketMQ相比,訊息模型是一樣的,區別在于RocketMQ中的“佇列”,在Kafka中,被替換成“磁區”,
作者:李潘 出處:http://wing011203.cnblogs.com/ 本文著作權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/545983.html
標籤:架構設計
