Kafka 網(wǎng)絡(luò)中斷和網(wǎng)絡(luò)分區(qū)4種場(chǎng)景分析
摘要:本文主要帶來(lái) 4 種 Kafka 網(wǎng)絡(luò)中斷和網(wǎng)絡(luò)分區(qū)場(chǎng)景分析。
1. 單個(gè) broker 節(jié)點(diǎn)和 leader 節(jié)點(diǎn)網(wǎng)絡(luò)中斷
網(wǎng)絡(luò)中斷前:
broker-1 和 broker-0(leader)間的網(wǎng)絡(luò)中斷后,單邊中斷,zk 可用(zk-1 為 leader,zk-0 和 zk-2 為 follower,zk-0 會(huì)不可用,但 zk 集群可用,過(guò)程中可能會(huì)引起原本連在 zk-0 上的 broker 節(jié)點(diǎn)會(huì)先和 zk 斷開,再重新連接其他 zk 節(jié)點(diǎn),進(jìn)而引起 controller 切換、leader 選舉等,此次分析暫不考慮這種情況),leader、isr、controller 都不變
az2 內(nèi)的客戶端無(wú)法生產(chǎn)消費(fèi)(metadata 指明 leader 為 broker-0,而 az2 連不上 broker-0),az1/3 內(nèi)的客戶端可以生產(chǎn)消費(fèi),若 acks=-1,retries=1,則生產(chǎn)消息會(huì)失敗,error_code=7(REQUEST_TIMED_OUT)(因?yàn)?broker-1 在 isr 中,但無(wú)法同步數(shù)據(jù)),且會(huì)發(fā)兩次(因?yàn)?retries=1),broker-0 和 broker-2 中會(huì)各有兩條重復(fù)的消息,而 broker-1 中沒有;由于 broker-0 沒有同步數(shù)據(jù),因此會(huì)從 isr 中被剔除,controller 同步 metadata 和 leaderAndIsr,isr 更新為 [2,0]
網(wǎng)絡(luò)恢復(fù)后,數(shù)據(jù)同步,更新 isr
2. 單個(gè) broker 節(jié)點(diǎn)和 controller 節(jié)點(diǎn)網(wǎng)絡(luò)中斷
broker 和 controller 斷連,不影響生產(chǎn)消費(fèi),也不會(huì)出現(xiàn)數(shù)據(jù)不一致的情況
而當(dāng)發(fā)生 leader 和 isr 變化時(shí),controller 無(wú)法將 leader 和 isr 的變化更新給 broker,導(dǎo)致元數(shù)據(jù)不一致
broker-0 故障時(shí),controller(broker-2)感知,并根據(jù) replicas 選舉新的 leader 為 broker-1,但因?yàn)楹?broker-1 網(wǎng)絡(luò)中斷,無(wú)法同步給 broker-1,broker-1 緩存的 leader 依然是 broker-0,isr 為 [1,2,0];當(dāng)客戶端進(jìn)行生產(chǎn)消費(fèi)時(shí),如果從 broker-2 拿到 metadata,認(rèn)為 leader 為 1,訪問 broker-1 會(huì)返回 NOT_LEADER_OR_FOLLOWER;如果從 broker-1 拿到 metadata,認(rèn)為 leader 為 0,訪問 broker-0 失敗,都會(huì)導(dǎo)致生產(chǎn)消費(fèi)失敗
3. 非 controller 節(jié)點(diǎn)所在 az 被隔離(分區(qū))
zk-0 和 zk-1、zk-2 不通,少于半數(shù),az1 內(nèi) zk 不可用,broker-0 無(wú)法訪問 zk,不會(huì)發(fā)生 controller 選舉,controller 還是在 broker-1
網(wǎng)絡(luò)恢復(fù)后,broker-0 加入集群,并同步數(shù)據(jù)
3.1 三副本 partition(replicas:[1,0,2]),原 leader 在 broker-1(或 broker-2)
az1 內(nèi):
broker-0 無(wú)法訪問 zk,感知不到節(jié)點(diǎn)變化,metadata 不更新(leader:1,isr:[1,0,2]),依然認(rèn)為自己是 follower,leader 在 1;az1 內(nèi)的客戶端無(wú)法生產(chǎn)消費(fèi)
az2/3 內(nèi):
zk 可用,感知到 broker-0 下線,metadata 更新,且不發(fā)生 leader 切換(isr:[1,0,2] -> [1,2],leader:1);az2 和 az3 內(nèi)的客戶端可正常生產(chǎn)消費(fèi)
3.2 三副本 partition(replicas:[0,1,2]),原 leader 在 broker-0
az1 內(nèi):
zk-0 和 zk-1、zk-2 連接中斷,少于一半,az1 內(nèi) zk 集群不可用,Broker-0 連不上 zk,無(wú)法感知節(jié)點(diǎn)變化,且無(wú)法更新 isr,metadata 不變,leader 和 isr 都不變;az1 內(nèi)客戶端可以繼續(xù)向 broker-0 生產(chǎn)消費(fèi)
az2/3 內(nèi):
zk-1 和 zk-2 連通,zk 可用,集群感知到 broker-0 下線,觸發(fā) leader 切換,broker-1 成為新的 leader(時(shí)間取決于 zookeeper.session.timeout.ms),并更新 isr;az2/3 內(nèi)的客戶端可以向 broker-1 生產(chǎn)消費(fèi)
此時(shí),該分區(qū)出現(xiàn)了雙主現(xiàn)象,replica-0 和 replica-1 均為 leader,均可以進(jìn)行生產(chǎn)消費(fèi)
若兩個(gè)隔離域內(nèi)的客戶端都生產(chǎn)了消息,就會(huì)出現(xiàn)數(shù)據(jù)不一致的情況
示例:(假設(shè)網(wǎng)絡(luò)隔離前有兩條消息,leaderEpoch=0)
網(wǎng)絡(luò)隔離前:
az1 隔離后,分區(qū)雙主,az1 內(nèi)的客戶端寫入 3 條消息:c、d、e,az2/3 內(nèi)的客戶端寫入 2 條消息:f、g:
這里 leaderEpoch 增加 2,是因?yàn)橛袃纱卧黾?leaderEpoch 的操作:一次是 PartitionStateMachine 的 handleStateChanges to OnlinePartition 時(shí)的 leader 選舉,一次是 ReplicationStateMachine 的 handleStateChanges to OfflineReplica 時(shí)的 removeReplicasFromIsr
網(wǎng)絡(luò)恢復(fù)后:
由于 controller 在 broker-2,緩存和 zk 中的 leader 都是 broker-1,controller 會(huì)告知 broker-0 makerFollower,broker-0 隨即 add fetcher,會(huì)先從 leader(broker-1)獲取 leaderEpoch 對(duì)應(yīng)的 endOffset(通過(guò) OFFSET_FOR_LEADER_EPOCH),根據(jù)返回的結(jié)果進(jìn)行 truncate,然后開始 FETCH 消息,并根據(jù)消息中的 leaderEpoch 進(jìn)行 assign,以此和 leader 保持一致
待數(shù)據(jù)同步后,加入 isr,并更新 isr 為 [1,2,0]。之后在觸發(fā) preferredLeaderElection 時(shí),broker-0 再次成為 leader,并增加 leaderEpoch 為 3
在網(wǎng)絡(luò)隔離時(shí),若 az1 內(nèi)的客戶端 acks=-1,retries=3,會(huì)發(fā)現(xiàn)生產(chǎn)消息失敗,而數(shù)據(jù)目錄中有消息,且為生產(chǎn)消息數(shù)的 4 倍(每條消息重復(fù) 4 次)
有前面所述可知,網(wǎng)絡(luò)恢復(fù)后,offset2-13 的消息會(huì)被覆蓋,但因?yàn)檫@些消息在生產(chǎn)時(shí),acks=-1,給客戶端返回的是生產(chǎn)失敗的,因此也不算消息丟失
因此,考慮此種情況,建議客戶端 acks=-1
4. Controller 節(jié)點(diǎn)所在 az 被隔離(分區(qū))
4.1 Leader 節(jié)點(diǎn)未被隔離
網(wǎng)絡(luò)中斷后,az3 的 zk 不可用,broker-2(原 controller)從 zk 集群斷開,broker-0 和 broker-1 重新競(jìng)選 controller
最終 broker-0 選舉為 controller,而 broker-2 也認(rèn)為自己是 controller,出現(xiàn) controller 雙主,同時(shí)因連不上 zk,metadata 無(wú)法更新,az3 內(nèi)的客戶端無(wú)法生產(chǎn)消費(fèi),az1/2 內(nèi)的客戶端可以正常生產(chǎn)消費(fèi)
故障恢復(fù)后,broker-2 感知到 zk 連接狀態(tài)發(fā)生變化,會(huì)先 resign,再嘗試競(jìng)選 controller,發(fā)現(xiàn) broker-0 已經(jīng)是 controller 了,放棄競(jìng)選 controller,同時(shí),broker-0 會(huì)感知到 broker-2 上線,會(huì)同步 LeaderAndIsr 和 metadata 到 broker-2,并在 broker-2 同步數(shù)據(jù)后加入 isr
4.2 Leader 節(jié)點(diǎn)和 controller 為同一節(jié)點(diǎn),一起被隔離
隔離前,controller 和 leader 都在 broker-0:
隔離后,az1 網(wǎng)絡(luò)隔離,zk 不可用,broker-2 競(jìng)選為 controller,出現(xiàn) controller 雙主,同時(shí) replica-2 成為 leader,分區(qū)也出現(xiàn)雙主
此時(shí)的場(chǎng)景和 3.2 類似,此時(shí)生產(chǎn)消息,可能出現(xiàn)數(shù)據(jù)不一致
網(wǎng)絡(luò)恢復(fù)后的情況,也和 3.2 類似,broker-2 為 controller 和 leader,broker-0 根據(jù) leaderEpoch 進(jìn)行 truncate,從 broker-2 同步數(shù)據(jù)
加入 isr,然后通過(guò) preferredLeaderElection 再次成為 leader,leaderEpoch 加 1
5. 補(bǔ)充:故障場(chǎng)景引起數(shù)據(jù)不一致
5.1 數(shù)據(jù)同步瞬間故障
初始時(shí),broker-0 為 leader,broker-1 為 follower,各有兩條消息 a、b:
leader 寫入一條消息 c,還沒來(lái)得及同步到 follower,兩個(gè) broker 都故障了(如下電):
之后 broker-1 先啟動(dòng),成為 leader(0 和 1 都在 isr 中,無(wú)論 unclean.leader.election.enable 是否為 true,都能升主),并遞增 leaderEpoch:
然后 broker-0 啟動(dòng),此時(shí)為 follower,通過(guò) OFFSET_FOR_LEADER_EPOCH 從 broker-1 獲取 leaderEpoch=0 的 endOffset
broker-0 根據(jù) leader epoch endOffset 進(jìn)行 truncate:
之后正常生產(chǎn)消息和副本同步:
該過(guò)程,如果 acks=-1,則生產(chǎn)消息 c 時(shí),返回客戶端的是生產(chǎn)失敗,不算消息丟失;如果 acks=0 或 1,則消息 c 丟失
5.2 unclean.leader.election.enable=true 引起的數(shù)據(jù)丟失
還是這個(gè)例子,broker-0 為 leader,broker-1 為 follower,各有兩條消息 a、b,此時(shí) broker-1 宕機(jī),isr=[0]
在 broker-1 故障期間,生產(chǎn)消息 c,因?yàn)?broker-1 已經(jīng)不在 isr 中了,所以即使 acks=-1,也能生產(chǎn)成功
然后 broker-0 也宕機(jī),leader=-1,isr=[0]
此時(shí) broker-1 先拉起,若 unclean.leader.election.enable=true,那么即使 broker-1 不在 isr 中,因?yàn)?broker-1 是唯一活著的節(jié)點(diǎn),因此 broker-1 會(huì)選舉為 leader,并更新 leaderEpoch 為 2
這時(shí),broker-0 再拉起,會(huì)先通過(guò) OFFSET_FOR_LEADER_EPOCH,從 broker-1 獲取 epoch 信息,并進(jìn)行數(shù)據(jù)截?cái)?/p>
再進(jìn)行生產(chǎn)消息和副本同步
消息 c 丟失
以上就是Kafka 網(wǎng)絡(luò)中斷和網(wǎng)絡(luò)分區(qū)4種場(chǎng)景分析的詳細(xì)內(nèi)容,更多關(guān)于Kafka 網(wǎng)絡(luò)中斷網(wǎng)絡(luò)分區(qū)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于ZooKeeper的會(huì)話機(jī)制Session解讀
這篇文章主要介紹了關(guān)于ZooKeeper的會(huì)話機(jī)制Session解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02RestTemplate使用Proxy代理作為跳板發(fā)送請(qǐng)求
這篇文章主要為大家介紹了RestTemplate使用代理proxy作為跳板發(fā)送請(qǐng)求的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03解決java轉(zhuǎn)義json出現(xiàn)\u0000 等亂碼的問題
這篇文章主要介紹了解決java轉(zhuǎn)義json出現(xiàn)\u0000 等亂碼的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03Java服務(wù)假死之生產(chǎn)事故的排查與優(yōu)化問題
在服務(wù)器上通過(guò)curl命令調(diào)用一個(gè)Java服務(wù)的查詢接口,半天沒有任何響應(yīng),怎么進(jìn)行這一現(xiàn)象排查呢,下面小編給大家記一次生產(chǎn)事故的排查與優(yōu)化——Java服務(wù)假死問題,感興趣的朋友一起看看吧2022-07-07關(guān)于Java中配置ElasticSearch集群環(huán)境賬號(hào)密碼的問題
這篇文章主要介紹了Java中配置ElasticSearch集群環(huán)境賬號(hào)密碼的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04LinkedList學(xué)習(xí)示例模擬堆棧與隊(duì)列數(shù)據(jù)結(jié)構(gòu)
這篇文章主要介紹了LinkedList學(xué)習(xí)示例,模擬一個(gè)堆棧與隊(duì)列數(shù)據(jù)結(jié)構(gòu),大家參考使用吧2014-01-01一文帶你快速學(xué)會(huì)JDBC及獲取連接的五種方式
JDBC(Java Database Connectivity)是一個(gè)獨(dú)立于特定數(shù)據(jù)庫(kù)管理系統(tǒng)、通用的SQL數(shù)據(jù)庫(kù)存取和操作的公共接口,下面這篇文章主要給大家介紹了關(guān)于如何通過(guò)一文帶你快速學(xué)會(huì)JDBC及獲取連接的五種方式,需要的朋友可以參考下2022-09-09