一個(gè)能干掉90%候選人的Kafka面試連環(huán)炮
1、寫(xiě)在前面
面試大廠時(shí),一旦簡(jiǎn)歷上寫(xiě)了Kafka,幾乎必然會(huì)被問(wèn)到一個(gè)問(wèn)題:說(shuō)說(shuō)acks參數(shù)對(duì)消息持久化的影響?
這個(gè)acks參數(shù)在kafka的使用中,是非常核心以及關(guān)鍵的一個(gè)參數(shù),決定了很多東西。
所以無(wú)論是為了面試還是實(shí)際項(xiàng)目使用,大家都值得看一下這篇文章對(duì)Kafka的acks參數(shù)的分析,以及背后的原理。
2、如何保證宕機(jī)的時(shí)候數(shù)據(jù)不丟失?
如果要想理解這個(gè)acks參數(shù)的含義,首先就得搞明白kafka的高可用架構(gòu)原理。
比如下面的圖里就是表明了對(duì)于每一個(gè)Topic,我們都可以設(shè)置他包含幾個(gè)Partition,每個(gè)Partition負(fù)責(zé)存儲(chǔ)這個(gè)Topic一部分的數(shù)據(jù)。
然后Kafka的Broker集群中,每臺(tái)機(jī)器上都存儲(chǔ)了一些Partition,也就存放了Topic的一部分?jǐn)?shù)據(jù),這樣就實(shí)現(xiàn)了Topic的數(shù)據(jù)分布式存儲(chǔ)在一個(gè)Broker集群上。
但是有一個(gè)問(wèn)題,萬(wàn)一 一個(gè)Kafka Broker宕機(jī)了,此時(shí)上面存儲(chǔ)的數(shù)據(jù)不就丟失了嗎?
沒(méi)錯(cuò),這就是一個(gè)比較大的問(wèn)題了,分布式系統(tǒng)的數(shù)據(jù)丟失問(wèn)題,是他首先必須要解決的,一旦說(shuō)任何一臺(tái)機(jī)器宕機(jī),此時(shí)就會(huì)導(dǎo)致數(shù)據(jù)的丟失。
3、多副本冗余的高可用機(jī)制
所以如果大家去分析任何一個(gè)分布式系統(tǒng)的原理,比如說(shuō)zookeeper、kafka、redis cluster、elasticsearch、hdfs,等等,其實(shí)他都有自己內(nèi)部的一套多副本冗余的機(jī)制,多副本冗余幾乎是現(xiàn)在任何一個(gè)優(yōu)秀的分布式系統(tǒng)都一般要具備的功能。
在kafka集群中,每個(gè)Partition都有多個(gè)副本,其中一個(gè)副本叫做leader,其他的副本叫做follower,如下圖。
如上圖所示,假設(shè)一個(gè)Topic拆分為了3個(gè)Partition,分別是Partition0,Partiton1,Partition2,此時(shí)每個(gè)Partition都有2個(gè)副本。
比如Partition0有一個(gè)副本是Leader,另外一個(gè)副本是Follower,Leader和Follower兩個(gè)副本是分布在不同機(jī)器上的。
這樣的多副本冗余機(jī)制,可以保證任何一臺(tái)機(jī)器掛掉,都不會(huì)導(dǎo)致數(shù)據(jù)徹底丟失,因?yàn)槠鸫a還是有副本在別的機(jī)器上的。
4、多副本之間數(shù)據(jù)如何同步?
接著我們就來(lái)看看多個(gè)副本之間數(shù)據(jù)是如何同步的?其實(shí)任何一個(gè)Partition,只有Leader是對(duì)外提供讀寫(xiě)服務(wù)的
也就是說(shuō),如果有一個(gè)客戶端往一個(gè)Partition寫(xiě)入數(shù)據(jù),此時(shí)一般就是寫(xiě)入這個(gè)Partition的Leader副本。
然后Leader副本接收到數(shù)據(jù)之后,F(xiàn)ollower副本會(huì)不停的給他發(fā)送請(qǐng)求嘗試去拉取最新的數(shù)據(jù),拉取到自己本地后,寫(xiě)入磁盤(pán)中。如下圖所示:
5、ISR到底指的是什么東西?
既然大家已經(jīng)知道了Partiton的多副本同步數(shù)據(jù)的機(jī)制了,那么就可以來(lái)看看ISR是什么了。
ISR全稱是“In-Sync Replicas”,也就是保持同步的副本,他的含義就是,跟Leader始終保持同步的Follower有哪些。
大家可以想一下 ,如果說(shuō)某個(gè)Follower所在的Broker因?yàn)镴VM FullGC之類的問(wèn)題,導(dǎo)致自己卡頓了,無(wú)法及時(shí)從Leader拉取同步數(shù)據(jù),那么是不是會(huì)導(dǎo)致Follower的數(shù)據(jù)比Leader要落后很多?
所以這個(gè)時(shí)候,就意味著Follower已經(jīng)跟Leader不再處于同步的關(guān)系了。但是只要Follower一直及時(shí)從Leader同步數(shù)據(jù),就可以保證他們是處于同步的關(guān)系的。
所以每個(gè)Partition都有一個(gè)ISR,這個(gè)ISR里一定會(huì)有Leader自己,因?yàn)長(zhǎng)eader肯定數(shù)據(jù)是最新的,然后就是那些跟Leader保持同步的Follower,也會(huì)在ISR里。
6、acks參數(shù)的含義
鋪墊了那么多的東西,最后終于可以進(jìn)入主題來(lái)聊一下acks參數(shù)的含義了。
如果大家沒(méi)看明白前面的那些副本機(jī)制、同步機(jī)制、ISR機(jī)制,那么就無(wú)法充分的理解acks參數(shù)的含義,這個(gè)參數(shù)實(shí)際上決定了很多重要的東西。
首先這個(gè)acks參數(shù),是在KafkaProducer,也就是生產(chǎn)者客戶端里設(shè)置的
也就是說(shuō),你往kafka寫(xiě)數(shù)據(jù)的時(shí)候,就可以來(lái)設(shè)置這個(gè)acks參數(shù)。然后這個(gè)參數(shù)實(shí)際上有三種常見(jiàn)的值可以設(shè)置,分別是:0、1 和 all。
第一種選擇是把a(bǔ)cks參數(shù)設(shè)置為0,意思就是我的KafkaProducer在客戶端,只要把消息發(fā)送出去,不管那條數(shù)據(jù)有沒(méi)有在哪怕Partition Leader上落到磁盤(pán),我就不管他了,直接就認(rèn)為這個(gè)消息發(fā)送成功了。
如果你采用這種設(shè)置的話,那么你必須注意的一點(diǎn)是,可能你發(fā)送出去的消息還在半路。結(jié)果呢,Partition Leader所在Broker就直接掛了,然后結(jié)果你的客戶端還認(rèn)為消息發(fā)送成功了,此時(shí)就會(huì)導(dǎo)致這條消息就丟失了。
?第二種選擇是設(shè)置 acks = 1,意思就是說(shuō)只要Partition Leader接收到消息而且寫(xiě)入本地磁盤(pán)了,就認(rèn)為成功了,不管他其他的Follower有沒(méi)有同步過(guò)去這條消息了。
這種設(shè)置其實(shí)是kafka默認(rèn)的設(shè)置,大家請(qǐng)注意,劃重點(diǎn)!這是默認(rèn)的設(shè)置
也就是說(shuō),默認(rèn)情況下,你要是不管acks這個(gè)參數(shù),只要Partition Leader寫(xiě)成功就算成功?。
但是這里有一個(gè)問(wèn)題,萬(wàn)一Partition Leader剛剛接收到消息,F(xiàn)ollower還沒(méi)來(lái)得及同步過(guò)去,結(jié)果Leader所在的broker宕機(jī)了,此時(shí)也會(huì)導(dǎo)致這條消息丟失,因?yàn)槿思铱蛻舳艘呀?jīng)認(rèn)為發(fā)送成功了。
?最后一種情況,就是設(shè)置acks=all,這個(gè)意思就是說(shuō),Partition Leader接收到消息之后,還必須要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步過(guò)去,才能認(rèn)為這條消息是寫(xiě)入成功了。
如果說(shuō)Partition Leader剛接收到了消息,但是結(jié)果Follower沒(méi)有收到消息,此時(shí)Leader宕機(jī)了,那么客戶端會(huì)感知到這個(gè)消息沒(méi)發(fā)送成功,他會(huì)重試再次發(fā)送消息過(guò)去。
此時(shí)可能Partition 2的Follower變成Leader了,此時(shí)ISR列表里只有最新的這個(gè)Follower轉(zhuǎn)變成的Leader了,那么只要這個(gè)新的Leader接收消息就算成功了。?
7、最后的思考
acks=all 就可以代表數(shù)據(jù)一定不會(huì)丟失了嗎?
當(dāng)然不是,如果你的Partition只有一個(gè)副本,也就是一個(gè)Leader,任何Follower都沒(méi)有,你認(rèn)為acks=all有用嗎?
當(dāng)然沒(méi)用了,因?yàn)镮SR里就一個(gè)Leader,他接收完消息后宕機(jī),也會(huì)導(dǎo)致數(shù)據(jù)丟失。
所以說(shuō),這個(gè)acks=all,必須跟ISR列表里至少有2個(gè)以上的副本配合使用,起碼是有一個(gè)Leader和一個(gè)Follower才可以。
這樣才能保證說(shuō)寫(xiě)一條數(shù)據(jù)過(guò)去,一定是2個(gè)以上的副本都收到了才算是成功,此時(shí)任何一個(gè)副本宕機(jī),不會(huì)導(dǎo)致數(shù)據(jù)丟失。
所以希望大家把這篇文章好好理解一下,對(duì)大家出去面試,或者工作中用kafka都是很好的一個(gè)幫助。