前言
前一篇文章《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也並不遜色多少。
好了,以上就是我的個人分析,多有不足,希望能和小夥伴進行探討。