天天看點

Kafka如何保證消息的可靠性?

Kafka分布式,高可用存儲架構

總所周知,Kafka是一個分布式的、可分區的、可複制的消息系統。

也就是說一個topic中的消息是放在多個partition上的,可是當一台機器當機後不就會導緻部分消息不可消費嗎?是以Kafka還做了多副本備援,每個Partition都可以搞一個副本放在别的機器上,這樣某台機器當機,隻不過是Partition其中一個副本丢失。

如果某個Partition有多副本的話,Kafka會選舉其中一個Parititon副本作為Leader,然後其他的Partition副本是Follower。

隻有Leader Partition是對外提供讀寫操作的,Follower Partition就是從Leader Partition同步資料。

一旦Leader Partition當機了,就會選舉其他的Follower Partition作為新的Leader Partition對外提供讀寫服務,這就實作了高可用架構。

Kafka如何保證消息的可靠性?

Kafka寫入資料丢失問題

什麼情況會導緻Kafka中寫入資料會丢失呢?

大家都知道寫入資料都是往某個Partition的Leader寫入的,然後那個Partition的Follower會從Leader同步資料,但是這個同步過程是異步的。也就是說如果此時1條資料剛寫入Leader Partition1,還沒來得及同步給Follower,Leader Partiton1所在機器突然就當機了的話,此時就會選舉Partition1的Follower作為新的Leader對外提供服務,然後使用者就讀不到剛才寫入的那條資料了。因為Partition0的Follower上是沒有同步到最新的一條資料的,這個時候就會造成資料丢失的問題。

Kafka如何保證消息的可靠性?

Kafka的ISR機制

這個機制簡單來說,就是會自動給每個Partition維護一個ISR清單,這個清單裡一定會有Leader,然後還會包含跟Leader保持同步的Follower。

也就是說,隻要Leader的某個Follower一直跟他保持資料同步,那麼就會存在于ISR清單裡。

但是如果Follower因為自身發生一些問題,導緻不能及時的從Leader同步資料過去,那麼這個Follower就會被認為是“out-of-sync”,從ISR清單裡移除。

怎麼保證Kafka寫入的資料不丢失

  1. 每個Partition都至少得有1個Follower在ISR清單裡,跟上了Leader的資料同步
  2. 每次寫入資料的時候,都要求至少寫入Partition Leader成功,同時還有至少一個ISR裡的Follower也寫入成功,才算這個寫入是成功了

如果不滿足上述兩個條件,那就一直寫入失敗,讓生産系統不停的嘗試重試,直到滿足上述兩個條件,然後才能認為寫入成功

這個時候萬一leader當機,就可以切換到那個follower上去,那麼Follower上是有剛寫入的資料的,此時資料就不會丢失了。

關于第二點就需要去配置相應ack參數,才能保證寫入Kafka的資料不會丢失。

ack參數

acks參數,是在Kafka Producer,也就是生産者裡設定的。

這個參數實際上有三種常見的值可以設定,分别是:0、1 和 all。

  • ack = 0,意思就是我的Kafka Producer在用戶端,隻要把消息發送出去,不管那條資料有沒有在哪怕Partition Leader上落到磁盤,直接就認為這個消息發送成功了。
  • ack = 1,意思就是說隻要Partition Leader接收到消息而且寫入本地磁盤了,就認為成功了,不管他其他的Follower有沒有同步過去這條消息了。這種設定是kafka預設的設定
  • ack = all,意思就是說,Partition Leader接收到消息之後,還必須要求ISR清單裡跟Leader保持同步的那些Follower都要把消息同步過去,才能認為這條消息是寫入成功了。

采用這種設定,如果Partition Leader剛接收到了消息,但是結果Follower沒有收到消息,此時Leader當機了,那麼用戶端會感覺到這個消息沒發送成功,他會重試再次發送消息過去。

此時可能Partition 2的Follower變成Leader了,此時ISR清單裡隻有最新的這個Follower轉變成的Leader了,那麼隻要這個新的Leader接收消息就算成功了。這樣就可以大機率保證發送端發送的消息不會丢失。

消費端

唯一可能導緻消費者弄丢資料的情況:就是說,你已經消費到了這個消息,然後消費者那邊自動送出了 offset,讓 Kafka 以為你已經消費好了這個消息,但其實你才剛準備處理這個消息,但是還沒處理,消費端就挂了,此時這條消息就丢了。

解決方案:

關閉自動送出 offset,在處理完之後自己手動送出 offset,就可以保證資料不會丢。但是此時确實還是可能會有重複消費,比如你剛處理完,還沒送出 offset,結果自己挂了,此時肯定會重複消費一次,自己保證幂等性就好了。

繼續閱讀