您當前的位置:首頁 > 動漫

這個bug,你中招了嗎!!!

作者:由 石臻臻的雜貨鋪 發表于 動漫時間:2023-01-01

這個bug,你中招了嗎!!!

在這裡插入圖片描述

kafka管控平臺推薦使用 滴滴開源 的

Kafka運維管控平臺(戳我呀) 更符合國人的操作習慣 、更強大的管控能力 、更高效的問題定位能力 、更便捷的叢集運維能力 、更專業的資源治理 、更友好的運維生態 、

Hello~~ 大家好,我是石臻臻~~~~

這個bug,你中招了嗎!!!

在這裡插入圖片描述

今天這篇文章,給大家分享一下最近看kafka原始碼時候,困擾我幾天的疑惑,供大家一起思考討論,確定一下它是不是一個 Bug 歡迎留言一起探討!

這個 “ Bug ” ,發生在分割槽副本進行分配的時候, 為了讓大家更好的理解,我把kafka裡面所有情況的分割槽分配規則給大家詳細講解一下 「 不想看過程,可以直接看最後的總結部分 」

在kafka需要進行分割槽副本分配計算的地方有三個地方

「 Topic建立 」的時候

「 分割槽擴容 」的時候

「 分割槽副本重分配 」的時候

Part1副本分配方式

副本分配的幾個原則:

將副本平均分佈在所有的 Broker 上;

partition 的多個副本應該分配在不同的 Broker 上;

如果所有的 Broker 有機架資訊的話, partition 的副本應該分配到不同的機架上。

這裡我們為了描述簡單,不分析有機架的情況

不管是什麼時候的分配規則,最終呼叫的都是下面這個方法,為了分析分配情況,我加了一些日誌

這個bug,你中招了嗎!!!

透過這個分配方法我們可以得知,影響最終分配的方式有幾個變數

Broker List

的順序

起始隨機分配BrokerID

startIndex

第一個副本跟第二個副本的 起始間隔偏移量

nextReplicaShift

我們透過 建立Topic的情景來分析一下整體的分配規則;

1建立Topic分割槽分配

Topic的建立可以看:

你知道Kafka建立Topic這個過程做了哪些事情嗎?(附影片)

我們先看一個副本的分配情況

啟動5個Broker, 建立一個Topic, 分割槽數10 副本數 1

單副本分配

這個bug,你中招了嗎!!!

分配情況可以用如下圖表示

起始隨機索引是2

, 也就是說起始BrokerId= Broker-4; 那麼第一個副本P0-1(

Leader

)就從它開始分配了,後續的分配就是按照BrokerList就行遍歷平均分配了,這樣就讓每個分割槽的

Leader

副本都均勻的分配到了不同的Broker上; 因為是單副本分配,

newxtReplicaShit

這個引數並沒有用上;

多副本分配

啟動5個Broker, 建立一個Topic, 分割槽數10 副本數 3;(還是跟上面一樣,但是這個時候將副本數變成3個; 建立一個新的Topic = Test_Topic)

這個bug,你中招了嗎!!!

在這裡插入圖片描述

起始隨機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間隔是一樣的,可以看下圖,

這個bug,你中招了嗎!!!

這個間隔的含義理解了,那我們看看這個整體的分配佈局

從這裡我們不難看出:

隨機的startIndex

可以儘量的讓Leader不會分割槽堆積的情況,如果每次都是從0開始,那麼每個Topic建立的時候第一個分割槽都落在0,假設分割槽不多,那麼就會全部堆積到前面的Broker中,後面的Broker分配不到;

nextReplicaShitf:

儘量讓單個Topic的副本分配的更雜湊一些

2分割槽擴容分配方式

分割槽擴容的情況,也是呼叫上面的方法,分配規則都是一樣的; 但是入參卻又有一些不一樣

不一樣的地方,我把關鍵scala程式碼貼出來看看

這個bug,你中招了嗎!!!

在這裡插入圖片描述

最終也是呼叫了

AdminUtils。assignReplicasToBrokers

方法; 但是入參有些不同

Broker List

allBrokers

; 這裡

allBrokers

是從下面方法裡獲取的,從zk裡面拿到Brokers節點再進行排序之後的列表; 如{0,1,2,3,4,5}

這個bug,你中招了嗎!!!

startIndex:

在這裡並不是一個隨機值了,而是

existingAssignmentPartition0。head

獲取的值; 這個表示的是當前Topic的第一個分割槽的第一個副本 在

Brokerlist

中的索引值;

nextReplicaShitf:

這裡跟

startIndex

是一個值; 如果入參指定了

startIndex

nextReplicaShitf:

跟它一樣,如下圖程式碼

這個bug,你中招了嗎!!!

startPartitionId:

這裡的值是已經存在的分割槽數; 建立topic的時候這個值是0;

這個bug,你中招了嗎!!!

那麼那麼把上面建立的t2(10分割槽,3副本), 執行一下分割槽擴容,擴容到13個;

這個bug,你中招了嗎!!!

這是擴分割槽後的情況, 因為這裡剛好是 輪訓兩次再進行擴容的,可能看不出來問題,我們看另一個case

建立新Topic t5, 3個分割槽,1副本 如下

這個bug,你中招了嗎!!!

擴分割槽到5個,新增的分割槽分配如下

這個bug,你中招了嗎!!!

分配圖

這個bug,你中招了嗎!!!

如果要均衡分配的話,至少是 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,你中招了嗎!!!

你要麼就都排序,你要麼就都接著用上一次的列表不好嗎?

分析到這裡, 我們已經肯定確定 分割槽擴容有可能會造成分割槽分割槽不均衡的情況

雖然這種影響很小,你我可能根本感知不出來,但是如果整個叢集批次做擴容的時候, 會不會就擴大了這個問題的影響範圍呢?

到這裡我們可能不能確定說它是一個bug, 只是有一個懷疑的因子

但是如果建立Topic的時候就是有序的,那麼這裡就肯定不會出現擴容分割槽不均勻的情況啊!

那我們接著分析 分割槽副本重分配的方式

3分割槽副本重分配方式

分割槽副本重分配的原始碼解析過程請看:

3萬字長文嘔心瀝血教你徹底搞懂資料遷移原理(附配套教學影片)

這裡就不再贅述了,直接丟擲結果;

我們把上面擴容之後的topic = t5 來進行一下重分配,看看kafka會給我們推薦什麼樣子的分配方式;

這個bug,你中招了嗎!!!

在這裡插入圖片描述

看圖,我可以分析得出, brokerList = {0,1,2,3,4} ; 不管你執行幾次

——generate

它的brokerList 都是{0,1,2,3,4} 有序的; 當然

startIndex

nextReplicaShift

都還是隨機的;

至少重新分配之後, 分割槽是均衡的了

而且看原始碼, 是特意排序過的

憑什麼只有建立Topic的時候不排序?

這個bug,你中招了嗎!!!

好,我思考思考,可能是有意為之,有一些其他的考量; 那麼再貼出來建立Topic的時候Broker List的原始碼

這個bug,你中招了嗎!!!

這個bug,你中招了嗎!!!

再往上

這個bug,你中招了嗎!!!

這個bug,你中招了嗎!!!

在這裡插入圖片描述

這個bug,你中招了嗎!!!

在這裡插入圖片描述

重點是在最後一張圖

建立Topic拿到的Broker List 是Controller初始化的時候去zk裡面獲取的Broker節點;

先排序了!!!

然後透過這個BrokerID又去zk獲取每個Broker的具體資訊

返回結果最終

toMap

了放到Map物件去了,所以這也就是為什麼不是有序的原因了;

這裡排序不是有一點脫褲子放屁 多此一舉的感覺嗎

這個bug,你中招了嗎!!!

在這裡插入圖片描述

Part2總結

那是不是bug呢? 我認為是的, 理由有以下幾點

現有的情況,在擴分割槽的時候有可能會造成分割槽分配不均勻的情況

「 Topic建立 」的時候沒有排序,可是「 擴分割槽」 、「 重分配 」 卻又是排序了

「 Topic建立 」的時候沒有排序,可是「 擴分割槽」的時候,它的計算邏輯是按照原有的分配方式就是順序的

如果建立的時候是順序的,那麼「 擴分割槽」造成分配不均勻的情況就不會出現

「 Topic建立 」的時候,它先是排序了,可是最後卻放到Map裡面了,如果它不是最終想排序,為啥一開始的時候就排序?,因為這裡的排序完全沒有必要;

以上是我分析的過程,和我的觀點,水平有限,歡迎提出不同看法,評論區討論!

這個bug,你中招了嗎!!!

在這裡插入圖片描述

標簽: 分割槽  副本  分配  topic  broker