本文內(nèi)容思維導圖: “RabbitMQ?”“Kafka?”“RocketMQ?”...在日常學習與開發(fā)過程中,我們常常聽到消息隊列這個關(guān)鍵詞。我也在我的多篇文章中提到了這個概念。可能你是熟練使用消息隊列的老手,又或者你是不懂消息隊列的新手,不論你了不了解消息隊列,本文都將帶你搞懂消息隊列的一些基本理論。如果你是老手,你可能從本文學到你之前不曾注意的一些關(guān)于消息隊列的重要概念,如果你是新手,相信本文將是你打開消息隊列大門的一板磚。 一 什么是消息隊列我們可以把消息隊列比作是一個存放消息的容器,當我們需要使用消息的時候可以取出消息供自己使用。消息隊列是分布式系統(tǒng)中重要的組件,使用消息隊列主要是為了通過異步處理提高系統(tǒng)性能和削峰、降低系統(tǒng)耦合性。目前使用較多的消息隊列有ActiveMQ,RabbitMQ,Kafka,RocketMQ,我們后面會一一對比這些消息隊列。 另外,我們知道隊列 Queue 是一種先進先出的數(shù)據(jù)結(jié)構(gòu),所以消費消息時也是按照順序來消費的。比如生產(chǎn)者發(fā)送消息1,2,3...對于消費者就會按照1,2,3...的順序來消費。但是偶爾也會出現(xiàn)消息被消費的順序不對的情況,比如某個消息消費失敗又或者一個 queue 多個consumer 也會導致消息被消費的順序不對,我們一定要保證消息被消費的順序正確。 除了上面說的消息消費順序的問題,使用消息隊列,我們還要考慮如何保證消息不被重復消費?如何保證消息的可靠性傳輸(如何處理消息丟失的問題)?......等等問題。所以說使用消息隊列也不是十全十美的,使用它也會讓系統(tǒng)可用性降低、復雜度提高,另外需要我們保障一致性等問題。 二 為什么要用消息隊列我覺得使用消息隊列主要有兩點好處:1.通過異步處理提高系統(tǒng)性能(削峰、減少響應所需時間);2.降低系統(tǒng)耦合性。如果在面試的時候你被面試官問到這個問題的話,一般情況是你在你的簡歷上涉及到消息隊列這方面的內(nèi)容,這個時候推薦你結(jié)合你自己的項目來回答。 《大型網(wǎng)站技術(shù)架構(gòu)》第四章和第七章均有提到消息隊列對應用性能及擴展性的提升。 (1) 通過異步處理提高系統(tǒng)性能(削峰、減少響應所需時間)
通過以上分析我們可以得出消息隊列具有很好的削峰作用的功能——即通過異步處理,將短時間高并發(fā)產(chǎn)生的事務(wù)消息存儲在消息隊列中,從而削平高峰期的并發(fā)事務(wù)。 舉例:在電子商務(wù)一些秒殺、促銷活動中,合理使用消息隊列可以有效抵御促銷活動剛開始大量訂單涌入對系統(tǒng)的沖擊。如下圖所示: 因為用戶請求數(shù)據(jù)寫入消息隊列之后就立即返回給用戶了,但是請求數(shù)據(jù)在后續(xù)的業(yè)務(wù)校驗、寫數(shù)據(jù)庫等操作中可能失敗。因此使用消息隊列進行異步處理之后,需要適當修改業(yè)務(wù)流程進行配合,比如用戶在提交訂單之后,訂單數(shù)據(jù)寫入消息隊列,不能立即返回用戶訂單提交成功,需要在消息隊列的訂單消費者進程真正處理完該訂單之后,甚至出庫后,再通過電子郵件或短信通知用戶訂單成功,以免交易糾紛。這就類似我們平時手機訂火車票和電影票。 (2) 降低系統(tǒng)耦合性我們知道如果模塊之間不存在直接調(diào)用,那么新增模塊或者修改模塊就對其他模塊影響較小,這樣系統(tǒng)的可擴展性無疑更好一些。 我們最常見的事件驅(qū)動架構(gòu)類似生產(chǎn)者消費者模式,在大型網(wǎng)站中通常用利用消息隊列實現(xiàn)事件驅(qū)動結(jié)構(gòu)。如下圖所示: 消息隊列使利用發(fā)布-訂閱模式工作,消息發(fā)送者(生產(chǎn)者)發(fā)布消息,一個或多個消息接受者(消費者)訂閱消息。 從上圖可以看到消息發(fā)送者(生產(chǎn)者)和消息接受者(消費者)之間沒有直接耦合,消息發(fā)送者將消息發(fā)送至分布式消息隊列即結(jié)束對消息的處理,消息接受者從分布式消息隊列獲取該消息后進行后續(xù)處理,并不需要知道該消息從何而來。對新增業(yè)務(wù),只要對該類消息感興趣,即可訂閱該消息,對原有系統(tǒng)和業(yè)務(wù)沒有任何影響,從而實現(xiàn)網(wǎng)站業(yè)務(wù)的可擴展性設(shè)計。 消息接受者對消息進行過濾、處理、包裝后,構(gòu)造成一個新的消息類型,將消息繼續(xù)發(fā)送出去,等待其他消息接受者訂閱該消息。因此基于事件(消息對象)驅(qū)動的業(yè)務(wù)架構(gòu)可以是一系列流程。 另外為了避免消息隊列服務(wù)器宕機造成消息丟失,會將成功發(fā)送到消息隊列的消息存儲在消息生產(chǎn)者服務(wù)器上,等消息真正被消費者服務(wù)器處理后才刪除消息。在消息隊列服務(wù)器宕機后,生產(chǎn)者服務(wù)器會選擇分布式消息隊列服務(wù)器集群中的其他服務(wù)器發(fā)布消息。 備注: 不要認為消息隊列只能利用發(fā)布-訂閱模式工作,只不過在解耦這個特定業(yè)務(wù)環(huán)境下是使用發(fā)布-訂閱模式的。除了發(fā)布-訂閱模式,還有點對點訂閱模式(一個消息只有一個消費者),我們比較常用的是發(fā)布-訂閱模式。 另外,這兩種消息模型是 JMS 提供的,AMQP 協(xié)議還提供了 5 種消息模型。 三 使用消息隊列帶來的一些問題
四 JMS VS AMQP4.1 JMS4.1.1 JMS 簡介JMS(JAVA Message Service,java消息服務(wù))是java的消息服務(wù),JMS的客戶端之間可以通過JMS服務(wù)進行異步的消息傳輸。JMS(JAVA Message Service,Java消息服務(wù))API是一個消息服務(wù)的標準或者說是規(guī)范,允許應用程序組件基于JavaEE平臺創(chuàng)建、發(fā)送、接收和讀取消息。它使分布式通信耦合度更低,消息服務(wù)更加可靠以及異步性。 ActiveMQ 就是基于 JMS 規(guī)范實現(xiàn)的。 4.1.2 JMS兩種消息模型①點到點(P2P)模型
② 發(fā)布/訂閱(Pub/Sub)模型
4.1.3 JMS 五種不同的消息正文格式JMS定義了五種不同的消息正文格式,以及調(diào)用的消息類型,允許你發(fā)送并接收以一些不同形式的數(shù)據(jù),提供現(xiàn)有消息格式的一些級別的兼容性。
4.2 AMQPAMQP,即Advanced Message Queuing Protocol,一個提供統(tǒng)一消息服務(wù)的應用層標準 高級消息隊列協(xié)議(二進制應用層協(xié)議),是應用層協(xié)議的一個開放標準,為面向消息的中間件設(shè)計,兼容 JMS。基于此協(xié)議的客戶端與消息中間件可傳遞消息,并不受客戶端/中間件同產(chǎn)品,不同的開發(fā)語言等條件的限制。 RabbitMQ 就是基于 AMQP 協(xié)議實現(xiàn)的。 4.3 JMS vs AMQP
總結(jié):
五 常見的消息隊列對比
總結(jié):
|
|