今天這篇文章,給大家分享一下最近看kafka源碼時候,困擾我幾天的疑惑,供大家一起思考讨論,确定一下它是不是一個 Bug 歡迎留言一起探讨!
這個 " Bug " ,發生在分區副本進行配置設定的時候, 為了讓大家更好的了解,我把kafka裡面所有情況的分區配置設定規則給大家詳細講解一下 「 不想看過程,可以直接看最後的總結部分 」
在kafka需要進行分區副本配置設定計算的地方有三個地方
- 「 Topic建立 」的時候
- 「 分區擴容 」的時候
- 「 分區副本重配置設定 」的時候
副本配置設定方式
副本配置設定的幾個原則:
- 将副本平均分布在所有的 Broker 上;
- partition 的多個副本應該配置設定在不同的 Broker 上;
- 如果所有的 Broker 有機架資訊的話, partition 的副本應該配置設定到不同的機架上。
這裡我們為了描述簡單,不分析有機架的情況
不管是什麼時候的配置設定規則,最終調用的都是下面這個方法,為了分析配置設定情況,我加了一些日志

通過這個配置設定方法我們可以得知,影響最終配置設定的方式有幾個變量
-
的順序Broker List
- 起始随機配置設定BrokerID
startIndex
- 第一個副本跟第二個副本的 起始間隔偏移量
nextReplicaShift
我們通過 建立Topic的情景來分析一下整體的配置設定規則;
建立Topic分區配置設定
Topic的建立可以看: [你知道Kafka建立Topic這個過程做了哪些事情嗎?]
我們先看一個副本的配置設定情況
啟動5個Broker, 建立一個Topic, 分區數10 副本數 1
單副本配置設定
配置設定情況可以用如下圖表示
起始随機索引是2
, 也就是說起始BrokerId= Broker-4; 那麼第一個副本P0-1(
Leader
)就從它開始配置設定了,後續的配置設定就是按照BrokerList就行周遊平均配置設定了,這樣就讓每個分區的
Leader
副本都均勻的配置設定到了不同的Broker上; 因為是單副本配置設定,
newxtReplicaShit
這個參數并沒有用上;
多副本配置設定
啟動5個Broker, 建立一個Topic, 分區數10 副本數 3;(還是跟上面一樣,但是這個時候将副本數變成3個; 建立一個新的Topic = Test_Topic)
!](https://upload-images.jianshu.io/upload_images/28446384-2ac2077f81498710.png?imageMogr2/auto-orient/strip|imageView2/2/w/1240)
起始随機startIndex:2currentPartitionId:0;起始随機nextReplicaShift:4;brokerArray:ArrayBuffer(0, 1, 4, 2, 3)
(p-0,ArrayBuffer(4, 2, 3))
(p-1,ArrayBuffer(2, 3, 0))
(p-2,ArrayBuffer(3, 0, 1))
(p-3,ArrayBuffer(0, 1, 4))
(p-4,ArrayBuffer(1, 4, 2))
變更nextReplicaShift:5
(p-5,ArrayBuffer(4, 3, 0))
(p-6,ArrayBuffer(2, 0, 1))
(p-7,ArrayBuffer(3, 1, 4))
(p-8,ArrayBuffer(0, 4, 2))
(p-9,ArrayBuffer(1, 2, 3))
複制代碼
這個得到的排列最終會寫的zk中, 這些就是AR的值; 第一個為Leader
-
= {0,1,4,2,3}Broker List
-
= 2startIndes
-
= 4 這裡跟 nextReplicaShift
= 0 是一樣的 (nextReplicaShift
)nextReplicaShift%(BrokerSize-1)
這裡跟單副本的時候基本上參數是一樣,
nextReplicaShift
= 4 表示的是 第一副本和第二副本起始間隔4, 總共5個Broker,最終效果和起始0間隔是一樣的,可以看下圖,
這個間隔的含義了解了,那我們看看這個整體的配置設定布局
從這裡我們不難看出:
随機的startIndex
可以盡量的讓Leader不會分區堆積的情況,如果每次都是從0開始,那麼每個Topic建立的時候第一個分區都落在0,假設分區不多,那麼就會全部堆積到前面的Broker中,後面的Broker配置設定不到;
nextReplicaShitf:
盡量讓單個Topic的副本配置設定的更散列一些
分區擴容配置設定方式
分區擴容的情況,也是調用上面的方法,配置設定規則都是一樣的; 但是入參卻又有一些不一樣
不一樣的地方,我把關鍵scala代碼貼出來看看
最終也是調用了
AdminUtils.assignReplicasToBrokers
方法; 但是入參有些不同
-
是Broker List
; 這裡allBrokers
是從下面方法裡擷取的,從zk裡面拿到Brokers節點再進行排序之後的清單; 如{0,1,2,3,4,5}allBrokers
-
在這裡并不是一個随機值了,而是startIndex:
擷取的值; 這個表示的是目前Topic的第一個分區的第一個副本 在existingAssignmentPartition0.head
中的索引值;Brokerlist
-
這裡跟nextReplicaShitf:
是一個值; 如果入參指定了startIndex
則startIndex
跟它一樣,如下圖代碼nextReplicaShitf:
-
這裡的值是已經存在的分區數; 建立topic的時候這個值是0; [圖檔上傳失敗...(image-522218-1669001591923)]startPartitionId:
那麼那麼把上面建立的t2(10分區,3副本), 執行一下分區擴容,擴容到13個;
這是擴分區後的情況, 因為這裡剛好是 輪訓兩次再進行擴容的,可能看不出來問題,我們看另一個case
建立新Topic t5, 3個分區,1副本 如下
擴分區到5個,新增的分區配置設定如下
配置設定圖
如果要均衡配置設定的話,至少是 1、1、1、1、1 才算是均衡,現在是直接有一個Broker沒有用上了;
為什麼會出現這種情況?
我們先分析一下 寫這段代碼的人想做什麼?
上圖左邊是最終擴容之後的配置設定,右邊是擴容時候的計算方式; 從上我們可以分析得出
- 分區擴容不會變更之前的配置設定情況,隻會變更重新計算擴容的那部分分區的配置設定規則;
-
是第一分區的第一個副本在排序之後的BrokerList中的索引值; 然後按照配置設定規則進行配置設定,并且這個時候有starIndex
截斷前面的配置,隻計算擴分區的這一部分;startPartitionId
從它這代碼分析不就是想接着上一次繼續配置設定嗎?它把Broker List 排序了; 然後又是接着原來的計算方式進行配置設定 ①.
starIndex
會讓起始的分區副本相同, ok,這個變量相同了 ②.
nextReplicaShitf
這個變量不會影響分區的Leader均衡,它的作用是盡量的離散一下副本
上面2個變量确定了,那麼隻要保證 第三個變量
broker List
的順序,那麼配置設定肯定就跟建立的時候一樣(排除手動改掉的情況); 也就會總體配置設定均衡了; 那麼實際情況
broker List
這個變量相同嗎?
答案: 不相同!!!!!
建立的時候是 {0,1,4,2,3} 未經過排序 擴分區的時候 {0,1,2,3,4} 經過了排序
你要麼就都排序,你要麼就都接着用上一次的清單不好嗎?
分析到這裡, 我們已經肯定确定 分區擴容有可能會造成分區分區不均衡的情況
雖然這種影響很小,你我可能根本感覺不出來,但是如果整個叢集批量做擴容的時候, 會不會就擴大了這個問題的影響範圍呢?
到這裡我們可能不能确定說它是一個bug, 隻是有一個懷疑的因子
但是如果建立Topic的時候就是有序的,那麼這裡就肯定不會出現擴容分區不均勻的情況啊!
那我們接着分析 分區副本重配置設定的方式
分區副本重配置設定方式
分區副本重配置設定的源碼解析過程請看:[3萬字長文嘔心瀝血教你徹底搞懂資料遷移原理(附配套教學視訊)
這裡就不再贅述了,直接抛出結果;
我們把上面擴容之後的topic = t5 來進行一下重配置設定,看看kafka會給我們推薦什麼樣子的配置設定方式;
看圖,我可以分析得出, brokerList = {0,1,2,3,4} ; 不管你執行幾次
--generate
它的brokerList 都是{0,1,2,3,4} 有序的; 當然
startIndex
和
nextReplicaShift
都還是随機的;
至少重新配置設定之後, 分區是均衡的了
而且看源碼, 是特意排序過的
憑什麼隻有建立Topic的時候不排序?
好,我思考思考,可能是有意為之,有一些其他的考量; 那麼再貼出來建立Topic的時候Broker List的源碼
再往上
- 先排序了!!!
- 然後通過這個BrokerID又去zk擷取每個Broker的具體資訊
- 傳回結果最終
了放到Map對象去了,是以這也就是為什麼不是有序的原因了;toMap
總結
- 現有的情況,在擴分區的時候有可能會造成分區配置設定不均勻的情況
- 「 Topic建立 」的時候沒有排序,可是「 擴分區」 、「 重配置設定 」 卻又是排序了
- 「 Topic建立 」的時候沒有排序,可是「 擴分區」的時候,它的計算邏輯是按照原有的配置設定方式就是順序的
- 如果建立的時候是順序的,那麼「 擴分區」造成配置設定不均勻的情況就不會出現
- 「 Topic建立 」的時候,它先是排序了,可是最後卻放到Map裡面了,如果它不是最終想排序,為啥一開始的時候就排序?,因為這裡的排序完全沒有必要;