這個bug,你中招了嗎!!!
在這裡插入圖片描述
kafka管控平臺推薦使用 滴滴開源 的
Kafka運維管控平臺(戳我呀) 更符合國人的操作習慣 、更強大的管控能力 、更高效的問題定位能力 、更便捷的叢集運維能力 、更專業的資源治理 、更友好的運維生態 、
Hello~~ 大家好,我是石臻臻~~~~
在這裡插入圖片描述
今天這篇文章,給大家分享一下最近看kafka原始碼時候,困擾我幾天的疑惑,供大家一起思考討論,確定一下它是不是一個 Bug 歡迎留言一起探討!
這個 “ Bug ” ,發生在分割槽副本進行分配的時候, 為了讓大家更好的理解,我把kafka裡面所有情況的分割槽分配規則給大家詳細講解一下 「 不想看過程,可以直接看最後的總結部分 」
在kafka需要進行分割槽副本分配計算的地方有三個地方
「 Topic建立 」的時候
「 分割槽擴容 」的時候
「 分割槽副本重分配 」的時候
Part1副本分配方式
副本分配的幾個原則:
將副本平均分佈在所有的 Broker 上;
partition 的多個副本應該分配在不同的 Broker 上;
如果所有的 Broker 有機架資訊的話, partition 的副本應該分配到不同的機架上。
這裡我們為了描述簡單,不分析有機架的情況
不管是什麼時候的分配規則,最終呼叫的都是下面這個方法,為了分析分配情況,我加了一些日誌
透過這個分配方法我們可以得知,影響最終分配的方式有幾個變數
Broker List
的順序
起始隨機分配BrokerID
startIndex
第一個副本跟第二個副本的 起始間隔偏移量
nextReplicaShift
我們透過 建立Topic的情景來分析一下整體的分配規則;
1建立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)
在這裡插入圖片描述
起始隨機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
Broker List
= {0,1,4,2,3}
startIndes
= 2
nextReplicaShift
= 4 這裡跟
nextReplicaShift
= 0 是一樣的 (
nextReplicaShift%(BrokerSize-1)
)
這裡跟單副本的時候基本上引數是一樣,
nextReplicaShift
= 4 表示的是 第一副本和第二副本起始間隔4, 總共5個Broker,最終效果和起始0間隔是一樣的,可以看下圖,
這個間隔的含義理解了,那我們看看這個整體的分配佈局
從這裡我們不難看出:
隨機的startIndex
可以儘量的讓Leader不會分割槽堆積的情況,如果每次都是從0開始,那麼每個Topic建立的時候第一個分割槽都落在0,假設分割槽不多,那麼就會全部堆積到前面的Broker中,後面的Broker分配不到;
nextReplicaShitf:
儘量讓單個Topic的副本分配的更雜湊一些
2分割槽擴容分配方式
分割槽擴容的情況,也是呼叫上面的方法,分配規則都是一樣的; 但是入參卻又有一些不一樣
不一樣的地方,我把關鍵scala程式碼貼出來看看
在這裡插入圖片描述
最終也是呼叫了
AdminUtils。assignReplicasToBrokers
方法; 但是入參有些不同
Broker List
是
allBrokers
; 這裡
allBrokers
是從下面方法裡獲取的,從zk裡面拿到Brokers節點再進行排序之後的列表; 如{0,1,2,3,4,5}
startIndex:
在這裡並不是一個隨機值了,而是
existingAssignmentPartition0。head
獲取的值; 這個表示的是當前Topic的第一個分割槽的第一個副本 在
Brokerlist
中的索引值;
nextReplicaShitf:
這裡跟
startIndex
是一個值; 如果入參指定了
startIndex
則
nextReplicaShitf:
跟它一樣,如下圖程式碼
startPartitionId:
這裡的值是已經存在的分割槽數; 建立topic的時候這個值是0;
那麼那麼把上面建立的t2(10分割槽,3副本), 執行一下分割槽擴容,擴容到13個;
這是擴分割槽後的情況, 因為這裡剛好是 輪訓兩次再進行擴容的,可能看不出來問題,我們看另一個case
建立新Topic t5, 3個分割槽,1副本 如下
擴分割槽到5個,新增的分割槽分配如下
分配圖
如果要均衡分配的話,至少是 1、1、1、1、1 才算是均衡,現在是直接有一個Broker沒有用上了;
為什麼會出現這種情況?
我們先分析一下 寫這段程式碼的人想做什麼?
上圖左邊是最終擴容之後的分配,右邊是擴容時候的計算方式; 從上我們可以分析得出
分割槽擴容不會變更之前的分配情況,只會變更重新計算擴容的那部分分割槽的分配規則;
starIndex
是第一分割槽的第一個副本在排序之後的BrokerList中的索引值; 然後按照分配規則進行分配,並且這個時候有
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分割槽副本重分配方式
分割槽副本重分配的原始碼解析過程請看:
3萬字長文嘔心瀝血教你徹底搞懂資料遷移原理(附配套教學影片)
這裡就不再贅述了,直接丟擲結果;
我們把上面擴容之後的topic = t5 來進行一下重分配,看看kafka會給我們推薦什麼樣子的分配方式;
在這裡插入圖片描述
看圖,我可以分析得出, brokerList = {0,1,2,3,4} ; 不管你執行幾次
——generate
它的brokerList 都是{0,1,2,3,4} 有序的; 當然
startIndex
和
nextReplicaShift
都還是隨機的;
至少重新分配之後, 分割槽是均衡的了
而且看原始碼, 是特意排序過的
憑什麼只有建立Topic的時候不排序?
好,我思考思考,可能是有意為之,有一些其他的考量; 那麼再貼出來建立Topic的時候Broker List的原始碼
再往上
在這裡插入圖片描述
在這裡插入圖片描述
重點是在最後一張圖
建立Topic拿到的Broker List 是Controller初始化的時候去zk裡面獲取的Broker節點;
先排序了!!!
然後透過這個BrokerID又去zk獲取每個Broker的具體資訊
返回結果最終
toMap
了放到Map物件去了,所以這也就是為什麼不是有序的原因了;
這裡排序不是有一點脫褲子放屁 多此一舉的感覺嗎
在這裡插入圖片描述
Part2總結
那是不是bug呢? 我認為是的, 理由有以下幾點
現有的情況,在擴分割槽的時候有可能會造成分割槽分配不均勻的情況
「 Topic建立 」的時候沒有排序,可是「 擴分割槽」 、「 重分配 」 卻又是排序了
「 Topic建立 」的時候沒有排序,可是「 擴分割槽」的時候,它的計算邏輯是按照原有的分配方式就是順序的
如果建立的時候是順序的,那麼「 擴分割槽」造成分配不均勻的情況就不會出現
「 Topic建立 」的時候,它先是排序了,可是最後卻放到Map裡面了,如果它不是最終想排序,為啥一開始的時候就排序?,因為這裡的排序完全沒有必要;
以上是我分析的過程,和我的觀點,水平有限,歡迎提出不同看法,評論區討論!
在這裡插入圖片描述
下一篇:夢,真的有意義嗎?