消息隊列的比較與分析

最近開始總結消息隊列的一些特點,公司中現在用到的消息隊列是kafka,於是順帶結合下其他幾個消息隊列來比較一下

1、Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什麼優缺點?

特性 ActiveMQ RabbitMQ RocketMQ Kafka
單機吞吐量 萬級,比 RocketMQ、Kafka 低一個數量級 同 ActiveMQ 10 萬級,支撐高吞吐 10 萬級,高吞吐,一般配合大數據類的系統來進行實時數據計算、日誌採集等場景
topic 數量對吞吐量的影響     topic 可以達到幾百/幾千的級別,吞吐量會有較小幅度的下降,這是 RocketMQ 的一大優勢,在同等機器下,可以支撐大量的 topic topic 從幾十到幾百個時候,吞吐量會大幅度下降,在同等機器下,Kafka 儘量保證 topic 數量不要過多,如果要支撐大規模的 topic,需要增加更多的機器資源
時效性 ms 級 微秒級,這是 RabbitMQ 的一大特點,延遲最低 ms 級 延遲在 ms 級以內
可用性 高,基於主從架構實現高可用 同 ActiveMQ 非常高,分佈式架構 非常高,分佈式,一個數據多個副本,少數機器宕機,不會丟失數據,不會導致不可用
消息可靠性 有較低的概率丟失數據 基本不丟 經過參數優化配置,可以做到 0 丟失 同 RocketMQ
功能支持 MQ 領域的功能極其完備 基於 erlang 開發,併發能力很強,性能極好,延時很低 MQ 功能較爲完善,還是分佈式的,擴展性好 功能較爲簡單,主要支持簡單的 MQ 功能,在大數據領域的實時計算以及日誌採集被大規模使用

綜上,各種對比之後,有如下建議:

一般的業務系統要引入 MQ,最早大家都用 ActiveMQ,但是現在確實大家用的不多了,沒經過大規模吞吐量場景的驗證,社區也不是很活躍,所以大家還是算了吧,我個人不推薦用這個了;

後來大家開始用 RabbitMQ,但是確實 erlang 語言阻止了大量的 Java 工程師去深入研究和掌控它,對公司而言,幾乎處於不可控的狀態,但是確實人家是開源的,比較穩定的支持,活躍度也高;

不過現在確實越來越多的公司會去用 RocketMQ,確實很不錯,畢竟是阿里出品,但社區可能有突然黃掉的風險(目前 RocketMQ 已捐給 Apache,但 GitHub 上的活躍度其實不算高)對自己公司技術實力有絕對自信的,推薦用 RocketMQ,否則回去老老實實用 RabbitMQ 吧,人家有活躍的開源社區,絕對不會黃。

所以中小型公司,技術實力較爲一般,技術挑戰不是特別高,用 RabbitMQ 是不錯的選擇;大型公司,基礎架構研發實力較強,用 RocketMQ 是很好的選擇。

如果是大數據領域的實時計算、日誌採集等場景,用 Kafka 是業內標準的,絕對沒問題,社區活躍度很高,絕對不會黃,何況幾乎是全世界這個領域的事實性規範。

2、消息隊列的高可用性

    1、RabbitMQ 的高可用性

     RabbitMQ 是比較有代表性的,因爲是基於主從(非分佈式)做高可用性的,我們就以 RabbitMQ 爲例子講解第一種 MQ 的高可用性怎麼實現。

    RabbitMQ 有三種模式:單機模式、普通集羣模式、鏡像集羣模式。

  • 單機模式

      單機模式,就是 Demo 級別的,一般就是你本地啓動了玩玩兒的😄,沒人生產用單機模式。

  • 普通集羣模式(無高可用性)

         普通集羣模式,意思就是在多臺機器上啓動多個 RabbitMQ 實例,每個機器啓動一個。你創建的 queue,只會放在一個 RabbitMQ 實例上,但是每個實例都同步 queue 的元數據(元數據可以認爲是 queue 的一些配置信息,通過元數據,可以找到queue 所在實例)。你消費的時候,實際上如果連接到了另外一個實例,那麼那個實例會從 queue 所在實例上拉取數據過來。

這種方式確實很麻煩,也不怎麼好,沒做到所謂的分佈式,就是個普通集羣。因爲這導致你要麼消費者每次隨機連接一個實例然後拉取數據,要麼固定連接那個 queue 所在實例消費數據,前者有數據拉取的開銷,後者導致單實例性能瓶頸

而且如果那個放 queue 的實例宕機了,會導致接下來其他實例就無法從那個實例拉取,如果你開啓了消息持久化,讓 RabbitMQ 落地存儲消息的話,消息不一定會丟,得等這個實例恢復了,然後纔可以繼續從這個 queue 拉取數據。

所以這個事兒就比較尷尬了,這就沒有什麼所謂的高可用性這方案主要是提高吞吐量的,就是說讓集羣中多個節點來服務某個 queue 的讀寫操作。

  • 鏡像集羣模式(高可用性)

這種模式,纔是所謂的 RabbitMQ 的高可用模式。跟普通集羣模式不一樣的是,在鏡像集羣模式下,你創建的 queue,無論元數據還是 queue 裏的消息都會存在於多個實例上,就是說,每個 RabbitMQ 節點都有這個 queue 的一個完整鏡像,包含 queue 的全部數據的意思。然後每次你寫消息到 queue 的時候,都會自動把消息同步到多個實例的 queue 上。

那麼如何開啓這個鏡像集羣模式呢?其實很簡單,RabbitMQ 有很好的管理控制檯,就是在後臺新增一個策略,這個策略是鏡像集羣模式的策略,指定的時候是可以要求數據同步到所有節點的,也可以要求同步到指定數量的節點,再次創建 queue 的時候,應用這個策略,就會自動將數據同步到其他的節點上去了。

這樣的話,好處在於,你任何一個機器宕機了,沒事兒,其它機器(節點)還包含了這個 queue 的完整數據,別的 consumer 都可以到其它節點上去消費數據。壞處在於,第一,這個性能開銷也太大了吧,消息需要同步到所有機器上,導致網絡帶寬壓力和消耗很重!第二,這麼玩兒,不是分佈式的,就沒有擴展性可言了,如果某個 queue 負載很重,你加機器,新增的機器也包含了這個 queue 的所有數據,並沒有辦法線性擴展你的 queue。你想,如果這個 queue 的數據量很大,大到這個機器上的容量無法容納了,此時該怎麼辦呢?

    2、Kafka 的高可用性

Kafka 一個最基本的架構認識:由多個 broker 組成,每個 broker 是一個節點;你創建一個 topic,這個 topic 可以劃分爲多個 partition,每個 partition 可以存在於不同的 broker 上,每個 partition 就放一部分數據。

這就是天然的分佈式消息隊列,就是說一個 topic 的數據,是分散放在多個機器上的,每個機器就放一部分數據

實際上 RabbmitMQ 之類的,並不是分佈式消息隊列,它就是傳統的消息隊列,只不過提供了一些集羣、HA(High Availability, 高可用性) 的機制而已,因爲無論怎麼玩兒,RabbitMQ 一個 queue 的數據都是放在一個節點裏的,鏡像集羣下,也是每個節點都放這個 queue 的完整數據。

Kafka 0.8 以前,是沒有 HA 機制的,就是任何一個 broker 宕機了,那個 broker 上的 partition 就廢了,沒法寫也沒法讀,沒有什麼高可用性可言。

比如說,我們假設創建了一個 topic,指定其 partition 數量是 3 個,分別在三臺機器上。但是,如果第二臺機器宕機了,會導致這個 topic 的 1/3 的數據就丟了,因此這個是做不到高可用的。

Kafka 0.8 以後,提供了 HA 機制,就是 replica(複製品) 副本機制。每個 partition 的數據都會同步到其它機器上,形成自己的多個 replica 副本。所有 replica 會選舉一個 leader 出來,那麼生產和消費都跟這個 leader 打交道,然後其他 replica 就是 follower。寫的時候,leader 會負責把數據同步到所有 follower 上去,讀的時候就直接讀 leader 上的數據即可。只能讀寫 leader?很簡單,要是你可以隨意讀寫每個 follower,那麼就要 care 數據一致性的問題,系統複雜度太高,很容易出問題。Kafka 會均勻地將一個 partition 的所有 replica 分佈在不同的機器上,這樣纔可以提高容錯性。

這麼搞,就有所謂的高可用性了,因爲如果某個 broker 宕機了,沒事兒,那個 broker上面的 partition 在其他機器上都有副本的。如果這個宕機的 broker 上面有某個 partition 的 leader,那麼此時會從 follower 中重新選舉一個新的 leader 出來,大家繼續讀寫那個新的 leader 即可。這就有所謂的高可用性了。

寫數據的時候,生產者就寫 leader,然後 leader 將數據落地寫本地磁盤,接着其他 follower 自己主動從 leader 來 pull 數據。一旦所有 follower 同步好數據了,就會發送 ack 給 leader,leader 收到所有 follower 的 ack 之後,就會返回寫成功的消息給生產者。(當然,這只是其中一種模式,還可以適當調整這個行爲)

消費的時候,只會從 leader 去讀,但是隻有當一個消息已經被所有 follower 都同步成功返回 ack 的時候,這個消息纔會被消費者讀到。

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