消息隊列的一些知識

這裏總結一些MQ(Message Queue,消息隊列)的相關知識。前端

消息隊列的優勢java

解耦程序員

在傳統模式下,系統之間的耦合性太強,好比系統A在代碼中直接調用系統B和系統C的代碼,若是未來D系統接入,系統A還須要修改代碼。web

若是將消息寫入消息隊列,須要消息的系統本身從消息隊列中訂閱,在D系統接入的時候系統A也不須要作任何修改,達到了解耦的效果。面試

異步算法

在傳統模式下,一些非必要的業務邏輯以同步的方式運行,須要等待上一個業務邏輯執行完畢才能開始執行下一個業務邏輯,耗費等待的時間。數據庫

若是將消息寫入消息隊列,非必要的業務邏輯就能夠以異步的方式運行,加快了服務響應的速度。服務器

削峯網絡

在傳統模式下,當併發量大的時候,全部的請求都會直接懟到數據庫,形成數據庫鏈接異常,甚至宕機。架構

若是將消息寫入消息隊列,則系統A能夠慢慢地按照數據庫能處理的併發量,從消息隊列中慢慢拉取消息。在生產中,這個短暫的高峯期積壓是容許的。

消息隊列的缺點

咱們引入一個技術,要對這個技術的弊端有充分的認識,才能作好預防。一個使用了MQ的項目,若是連MQ的缺點都沒有考慮過,就把MQ引進去了,那就會給本身的項目帶來風險。

系統可用性下降

你想啊,原本其餘系統只要運行好好的,那你的系統就是正常的。如今你非要加個消息隊列進去,那消息隊列掛了,系統也就掛了。用專業的術語來解釋,就是系統的可用性下降了。

系統複雜性增長

加了MQ以後要多考慮不少方面的問題,好比數據的一致性問題、如何避免消息被重複消費,如何保證消息可靠傳輸等。所以,須要考慮的東西更多,系統複雜性也就隨着增長了。

消息隊列的選型

既然在項目中用了MQ,確定事先要對業界流行的MQ進行調研,若是連每種MQ的優缺點都沒了解清楚,隨便選用了某種MQ,就容易給項目挖坑。另外,若是面試官問爲何項目上選用這種MQ的時候,你直接回答是領導決定的,這種回答就很LOW了。因此瞭解一下各類MQ的優缺點和使用的場景仍是有必要的。

這裏只簡單說一下ActiveMQ、RabbitMQ、RocketMQ和Kafka四種MQ框架。

更新頻率

要了解各個MQ方案的更新頻率,能夠上各個MQ的官方社區去看。

簡單瞭解一下就是,ActiveMQ幾個月才發一次版本,聽說研究重心在他們的下一代產品Apollo;RabbitMQ的版本發佈比ActiveMQ頻繁不少;RocketMQ和Kafka也比ActiveMQ活躍的多。

性能對比

用一個表格簡單比較下各個MQ的性能。

特性 ActiveMQ RabbitMQ RocketMQ Kafka
開發語言 java erlang java scala
單機吞吐量 萬級 萬級 10萬級 10萬級
時效性 ms級 us級 ms級 ms級之內
可用性 高(主從架構) 高(主從架構) 很是高(分佈式架構) 很是高(分佈式架構)
功能特性 成熟的產品,在不少公司獲得應用;有較多的文檔;各類協議支持較好 基於erlang開發,因此併發能力很強,性能極其好,延時很低;管理界面較豐富 MQ功能比較完備,擴展性佳 只支持主要的MQ功能,像一些消息查詢,消息回溯等功能沒有提供,畢竟是爲大數據準備的,在大數據領域應用廣。

MQ選型的簡單總結

1.中小型軟件公司,建議選RabbitMQ。一方面,erlang語言天生具有高併發的特性,並且他的管理界面用起來十分方便。可是雖然RabbitMQ是開源的,國內能定製化開發erlang的程序員卻不多。所幸的是RabbitMQ的社區十分活躍,經過社區能夠解決開發過程當中遇到的大部分Bug,這點對於中小型公司來講十分重要。不考慮RocketMQ和Kafka的緣由是,一方面中小型軟件公司不如互聯網公司,數據量沒那麼大,選消息中間件,應首選功能比較完備的,因此Kafka排除。不考慮RocketMQ的緣由是,RocketMQ是阿里出品,一旦哪一天阿里放棄維護RocketMQ,中小型公司通常是抽不出人來進行RocketMQ的定製化開發的,所以不推薦。

2.大型軟件公司,根據具體使用在RocketMQ和Kafka之間二選一。一方面,大型軟件公司,具有足夠的資金搭建分佈式環境,也具有足夠大的數據量。針對RocketMQ,大型軟件公司也能夠抽出人手對RocketMQ進行定製化開發,畢竟國內有能力改Java源碼的人,仍是至關多的。至於Kafka,根據業務場景選擇,若是有日誌採集功能,確定是首選Kafka了。具體該選哪一個,仍是要看具體的使用場景。

保證消息隊列的高可用

前面說過了,引入消息隊列後,系統的可用性會下降。在生產中,沒人會使用單機模式的消息隊列,所以瞭解消息隊列的高可用是很必要的。實際上,要保證消息隊列的高可用,須要對消息隊列的集羣模式有深入瞭解。

RocketMQ保證消息隊列的高可用

以RocketMQ爲例,他的集羣就有多master模式、多master多slave異步複製模式和多master多slave同步雙寫模式。

下面是一張RocketMQ多master多slave模式部署的架構圖。

這樣的實現方式其實和Kafka很像,只是Name Server集羣在Kafka中是用Zookeeper代替,都是用來保存和發現Master和Slave用的。通訊過程以下:Producer與Name Server集羣中的其中一個節點(隨機選擇)創建長鏈接,按期從Name Server集羣獲取Topic路由信息,並向提供Topic服務的Broker Master創建長鏈接,且定時向Broker發送消息。Producer只能將消息發送到Broker Master,可是Consumer則不同,它同時和提供Topic服務的Master和Slave創建長鏈接,既能夠從Broker Master訂閱消息,也能夠從Broker Slave訂閱消息。

Kafka保證消息隊列的高可用

直接上Kafka的拓補架構圖來看Kafka的集羣模式。

 

如上圖所示,一個典型的Kafka集羣中包含若干Producer(能夠是web前端產生的Page View,或者是服務器日誌,系統CPU、Memory等),若干Broker(Kafka支持水平擴展,通常來講,Broker的數量越多,集羣的吞吐率就越高),若干Consumer Group,以及一個Zookeeper集羣。Kafka經過Zookeeper管理集羣配置,選舉Leader,以及在Consumer Group發生變化時進行rebalance。Producer使用push模式將消息發佈到Broker,Consumer使用pull模式從broker訂閱並消費消息。

RabbitMQ保證消息隊列的高可用

RabbitMQ也有普通集羣和鏡像集羣模式,比較簡單。

保證消息隊列高可用性的簡單總結

要保證消息隊列的高可用,須要從集羣上入手,具體就是當消息隊列中的一個節點炸了,其餘的節點還能繼續運行,保證消息隊列總體能正常運行。

另外,若是有相關的面試題,須要瞭解MQ集羣架構並能敘述清楚架構中的邏輯關係。

保證消息不被重複消費

保證消息不被重複消費,也就是保證消息隊列的冪等性。這個問題能夠認爲是消息隊列領域的基本問題。

消息被重複消費的緣由

不管是哪種消息隊列,形成消息被重複消費的緣由都是相似的。在正常的狀況下,消費者在消費消息完畢後,會發送一個確認信息給消息隊列,消息隊列就知道該消息被消費了,就會將該消息從消息隊列中刪除。只是不一樣的消息隊列發送的確認信息形式不一樣,例如RabbitMQ是發送一個ACK確認消息,RocketMQ是返回一個CONSUME_SUCCESS成功標誌,Kafka則其實是有個offset的概念(每個消息都有一個offset,Kafka消費過消息後,須要提交offset,讓消息隊列知道本身已經消費過了)。而形成重複消費的緣由,就是由於網絡傳輸等等故障,確認信息沒有傳送到消息隊列,致使消息隊列不知道本身已經消費過該消息了,再次將該消息分發給其餘的消費者。

消息被重複消費的解決方法

解決方法有不少,其實就是單機服務裏冪等性的問題,這裏簡單列舉幾個方法。

1.惟一索引。若是拿到的消息是作數據庫的insert操做,能夠給這個消息作一個惟一主鍵,那麼就算出現重複消費的狀況,也會由於主鍵衝突而取消操做,有效避免數據庫出現髒數據。

2.原生冪等。若是拿到的消息是作Redis的set的操做,由於在Redis中set操做原本就算冪等操做,即不管set幾回結果都是同樣的,也就不怕消息被重複消費的問題了。

3.全局狀態機。準備一個第三方介質,來作一個消息消費的記錄。以Redis爲例,給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V的形式寫入Redis。在消費者開始消費前,先去Redis中查詢有沒有消費記錄便可。

保證消息消費的可靠性傳輸

在使用消息隊列的過程當中,應該作到消息不能多消費,也不能少消費。若是沒法作到可靠性傳輸,可能給公司帶來千萬級別的財產損失。

而要保證消息消費的可靠性傳輸,每種MQ都要從三個角度來分析,分別是生產者弄丟數據、消息隊列弄丟數據和消費者弄丟數據。

這個內容太複雜了,暫時玩不轉,等之後再補充,嘿嘿。

保證消息的順序性

要保證消息的順序性,能夠經過某種算法,將須要保持前後順序的消息放到同一個消息隊列中(Kafka中就是Partition,RabbitMQ中就是Queue),而後只用一個消費者去消費該隊列便可。

另外,若是爲了吞吐量,有多個消費者去消費,這時候要保證消息的順序性,其實只要一個簡單的重試就行了。好比微博,能夠分爲發微博、寫評論和刪除微博這三個異步操做。若是這時候有一個消費者先執行了寫評論的操做,可是這時候,微博都還沒發,寫評論必定是失敗的,就能夠等一段時間再重試。等另外一個消費者,先執行發微博的操做後,再執行寫評論的操做,就能夠成功。

實際上,要保證消息的順序性,大多數狀況下只須要保證入隊有序就行,出隊之後的順序交給消費者本身去保證,沒有固定的套路。

 

"慢慢你們會明白的,沒法跟喜歡的人在一塊兒,實際上是人生的常態。"

相關文章
相關標籤/搜索