前言
前一篇文章《RabbitMQ和Kafka到底怎么選?》,我們在吞吐量方面比較了Kafka和RabbitMQ,知道了Kafka的吞吐量要高於RabbitMQ。本文從可靠性方面繼續探討兩個隊列的差異。
RabbitMQ可靠性
我們通過前文知道,RabbitMQ的隊列分為master queue和mirror queue,mirror queue 在master queue宕機之后,會被提升為master queue,如下圖所示。
隊列A的consumer在消費的時候,機器宕機,此時客戶端和服務端分別做如下動作:
- 服務端:把mirror queue提升為master queue
- 客戶端:連接到新的master queue 所在的節點進行消費或者生產
當master queue 所在節點宕機后,其正在被消費的消息的相關信息全部丟失,即服務端不知道消費者對那一瞬間消費的消息是否進行了ACK,所以在mirror queue被提升為master queue時,會把宕機前正在進行消費的的消息全部重新發送一遍,即客戶端重連后,消息可能被重復消費,這個時候就必須依靠應用層邏輯來判斷來避免重復消費。
在持久化方面,RabbitMQ的master queue每次收到新消息后,都會立刻寫入磁盤,並把消息同步給mirror queue。假設在master queue 收到消息后,消息未同步到mirror queue 之前master queue 宕機,則此時mirror queue中就沒有剛剛master queue收到的那條消息,當這個mirror queue被提升為master queue時,消費者連接到新的master queue上進行消費時就丟了一條消息。所以,RabbitMQ也會丟消息,只不過這個丟消息的概率非常低。
Kafka可靠性
我們知道Kafka中的每個隊列叫做Topic,一個Topic有多個主分片和副分片,當主分片所在機器宕機后,服務端會把一個副分片提升為主分片,如下圖所示。
服務端和客戶端會有如下動作:
- 服務端:把副分片提升為主分片
- 客戶端:連接到新的主分片
Kafka同樣有主從同步,所以也必定存在與RabbitMQ同樣丟消息的問題。但是Kafka的每個客戶端保存了讀取消息的偏移信息,故當一個主分片宕機后,Kafka客戶端可以從副分片相應位移后繼續消費,不會有重復消費的情況。
持久化方面,Kafka默認把消息直接寫文件,但是由於操作系統的cache原因,消息可能不會立馬寫到磁盤上,這個時候就需要刷新文件到磁盤。由於刷新文件到磁盤是一個比較耗時的操作,故Kafka提供了兩種不同的刷新配置:
#每接收多少條消息刷一下磁盤
log.flush.interval.messages=10000
#每隔多少ms刷一下磁盤
log.flush.interval.ms=1000
我們完全可以把log.flush.interval.messages設置為1,這樣Kafka就能在持久化方面達到和RabbitMQ同樣的安全級別。
但是Kafka集群依賴ZK,如上圖所示,所以對於Kafka穩定性的評估必須考慮ZK集群的穩定性,而一般我們認為任何分布式集群的穩定性都小於1,故兩個集群的串聯穩定性會下降一些,維護更復雜一些,這點沒有RabbitMQ有優勢。
總結
其實好多開源組件隨着時間推移,往往都進行了各種改進。就比如Kafka雖然是為了日志而生,給人第一印象是容易丟消息,但是經過這么多年的改進,其可靠性可能並不遜色RabbitMQ了,只需要你根據不同的業務場景配置不同的配置參數,即可達到適合自己的安全級別。
- 從吞吐量上看,在不要求消息順序情況下,Kafka完勝;在要求消息先后順序的場景,性能應該稍遜RabbitMQ(此時Kafka的分片數只能為1)。
- 從穩定性來看,RabbitMQ勝出,但是Kafka也並不遜色多少。
好了,以上就是我的個人分析,多有不足,希望能和小伙伴進行探討。