Kafka之acks引數對訊息持久化的影響

Mark_ZQ發表於2020-11-28

(0)寫在前面 

面試大廠時,一旦簡歷上寫了Kafka,幾乎必然會被問到一個問題:說說acks引數對訊息持久化的影響?

這個acks引數在kafka的使用中,是非常核心以及關鍵的一個引數,決定了很多東西。

所以無論是為了面試還是實際專案使用,大家都值得看一下這篇文章對Kafka的acks引數的分析,以及背後的原理。

 

(1)如何保證當機的時候資料不丟失?

如果要想理解這個acks引數的含義,首先就得搞明白kafka的高可用架構原理。

比如下面的圖裡就是表明了對於每一個Topic,我們都可以設定他包含幾個Partition,每個Partition負責儲存這個Topic一部分的資料。

然後Kafka的Broker叢集中,每臺機器上都儲存了一些Partition,也就存放了Topic的一部分資料,這樣就實現了Topic的資料分散式儲存在一個Broker叢集上。

https://img1.sycdn.imooc.com/5cc1c99d0001458702580355.jpg

但是有一個問題,萬一 一個Kafka Broker當機了,此時上面儲存的資料不就丟失了嗎?

沒錯,這就是一個比較大的問題了,分散式系統的資料丟失問題,是他首先必須要解決的,一旦說任何一臺機器當機,此時就會導致資料的丟失。

 

(2)多副本冗餘的高可用機制

所以如果大家去分析任何一個分散式系統的原理,比如說zookeeper、kafka、redis cluster、elasticsearch、hdfs,等等,其實他都有自己內部的一套多副本冗餘的機制,多副本冗餘幾乎是現在任何一個優秀的分散式系統都一般要具備的功能。

在kafka叢集中,每個Partition都有多個副本,其中一個副本叫做leader,其他的副本叫做follower,如下圖。

https://img4.sycdn.imooc.com/5cc1c9ae0001090702510342.jpg

如上圖所示,假設一個Topic拆分為了3個Partition,分別是Partition0,Partiton1,Partition2,此時每個Partition都有2個副本。

比如Partition0有一個副本是Leader,另外一個副本是Follower,Leader和Follower兩個副本是分佈在不同機器上的。

這樣的多副本冗餘機制,可以保證任何一臺機器掛掉,都不會導致資料徹底丟失,因為起碼還是有副本在別的機器上的。

 

(3)多副本之間資料如何同步?

接著我們就來看看多個副本之間資料是如何同步的?其實任何一個Partition,只有Leader是對外提供讀寫服務的

也就是說,如果有一個客戶端往一個Partition寫入資料,此時一般就是寫入這個Partition的Leader副本。

然後Leader副本接收到資料之後,Follower副本會不停的給他傳送請求嘗試去拉取最新的資料,拉取到自己本地後,寫入磁碟中。如下圖所示:

https://img3.sycdn.imooc.com/5cc1c9be0001d12e06670351.jpg

 

(4)ISR到底指的是什麼東西?

 

既然大家已經知道了Partiton的多副本同步資料的機制了,那麼就可以來看看ISR是什麼了。

ISR全稱是“In-Sync Replicas”,也就是保持同步的副本,他的含義就是,跟Leader始終保持同步的Follower有哪些。

大家可以想一下 ,如果說某個Follower所在的Broker因為JVM FullGC之類的問題,導致自己卡頓了,無法及時從Leader拉取同步資料,那麼是不是會導致Follower的資料比Leader要落後很多?

所以這個時候,就意味著Follower已經跟Leader不再處於同步的關係了。但是隻要Follower一直及時從Leader同步資料,就可以保證他們是處於同步的關係的。

所以每個Partition都有一個ISR,這個ISR裡一定會有Leader自己,因為Leader肯定資料是最新的,然後就是那些跟Leader保持同步的Follower,也會在ISR裡。

 

(5)acks引數的含義

 

鋪墊了那麼多的東西,最後終於可以進入主題來聊一下acks引數的含義了。

如果大家沒看明白前面的那些副本機制、同步機制、ISR機制,那麼就無法充分的理解acks引數的含義,這個引數實際上決定了很多重要的東西。

首先這個acks引數,是在KafkaProducer,也就是生產者客戶端裡設定的

也就是說,你往kafka寫資料的時候,就可以來設定這個acks引數。然後這個引數實際上有三種常見的值可以設定,分別是:0、1 和 all。

第一種選擇是把acks引數設定為0,意思就是我的KafkaProducer在客戶端,只要把訊息傳送出去,不管那條資料有沒有在哪怕Partition Leader上落到磁碟,我就不管他了,直接就認為這個訊息傳送成功了。

如果你採用這種設定的話,那麼你必須注意的一點是,可能你傳送出去的訊息還在半路。結果呢,Partition Leader所在Broker就直接掛了,然後結果你的客戶端還認為訊息傳送成功了,此時就會導致這條訊息就丟失了。

https://img1.sycdn.imooc.com/5cc1c9d900017d0e06950366.jpg

第二種選擇是設定 acks = 1,意思就是說只要Partition Leader接收到訊息而且寫入本地磁碟了,就認為成功了,不管他其他的Follower有沒有同步過去這條訊息了。

這種設定其實是kafka預設的設定,大家請注意,劃重點!這是預設的設定

也就是說,預設情況下,你要是不管acks這個引數,只要Partition Leader寫成功就算成功。

但是這裡有一個問題,萬一Partition Leader剛剛接收到訊息,Follower還沒來得及同步過去,結果Leader所在的broker當機了,此時也會導致這條訊息丟失,因為人家客戶端已經認為傳送成功了。

https://img3.sycdn.imooc.com/5cc1c9ed0001f4b606110353.jpg

最後一種情況,就是設定acks=all,這個意思就是說,Partition Leader接收到訊息之後,還必須要求ISR列表裡跟Leader保持同步的那些Follower都要把訊息同步過去,才能認為這條訊息是寫入成功了。

如果說Partition Leader剛接收到了訊息,但是結果Follower沒有收到訊息,此時Leader當機了,那麼客戶端會感知到這個訊息沒傳送成功,他會重試再次傳送訊息過去。

此時可能Partition 2的Follower變成Leader了,此時ISR列表裡只有最新的這個Follower轉變成的Leader了,那麼只要這個新的Leader接收訊息就算成功了。

https://img4.sycdn.imooc.com/5cc1c9fd0001915606690358.jpg

 

(6)最後的思考

 

acks=all 就可以代表資料一定不會丟失了嗎?

當然不是,如果你的Partition只有一個副本,也就是一個Leader,任何Follower都沒有,你認為acks=all有用嗎?

當然沒用了,因為ISR裡就一個Leader,他接收完訊息後當機,也會導致資料丟失。

所以說,這個acks=all,必須跟ISR列表裡至少有2個以上的副本配合使用,起碼是有一個Leader和一個Follower才可以。

這樣才能保證說寫一條資料過去,一定是2個以上的副本都收到了才算是成功,此時任何一個副本當機,不會導致資料丟失。

所以希望大家把這篇文章好好理解一下,對大家出去面試,或者工作中用kafka都是很好的一個幫助。

 


作者:石杉的架構筆記
連結:http://www.imooc.com/article/285818
來源:慕課網
本文原創釋出於慕課網 ,轉載請註明出處,謝謝合作

相關文章