天天看點

這個bug,你中招了嗎?

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

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

在kafka需要進行分區副本配置設定計算的地方有三個地方

  1. 「 Topic建立 」的時候
  2. 「 分區擴容 」的時候
  3. 「 分區副本重配置設定 」的時候

副本配置設定方式

副本配置設定的幾個原則:

  1. 将副本平均分布在所有的 Broker 上;
  2. partition 的多個副本應該配置設定在不同的 Broker 上;
  3. 如果所有的 Broker 有機架資訊的話, partition 的副本應該配置設定到不同的機架上。
這裡我們為了描述簡單,不分析有機架的情況

不管是什麼時候的配置設定規則,最終調用的都是下面這個方法,為了分析配置設定情況,我加了一些日志

這個bug,你中招了嗎?

通過這個配置設定方法我們可以得知,影響最終配置設定的方式有幾個變量

  1. ​Broker List​

    ​ 的順序
  2. 起始随機配置設定BrokerID ​

    ​startIndex​

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

    ​nextReplicaShift​

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

建立Topic分區配置設定

Topic的建立可以看: [你知道Kafka建立Topic這個過程做了哪些事情嗎?]

我們先看一個副本的配置設定情況

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

單副本配置設定

這個bug,你中招了嗎?

配置設定情況可以用如下圖表示

這個bug,你中招了嗎?

​起始随機索引是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

  1. ​Broker List​

    ​ = {0,1,4,2,3}
  2. ​startIndes​

    ​ = 2
  3. ​nextReplicaShift​

    ​ = 4 這裡跟 ​

    ​nextReplicaShift​

    ​ = 0 是一樣的 (​

    ​nextReplicaShift%(BrokerSize-1)​

    ​)

這裡跟單副本的時候基本上參數是一樣, ​

​nextReplicaShift​

​ = 4 表示的是 第一副本和第二副本起始間隔4, 總共5個Broker,最終效果和起始0間隔是一樣的,可以看下圖,

這個bug,你中招了嗎?

這個間隔的含義了解了,那我們看看這個整體的配置設定布局

這個bug,你中招了嗎?

從這裡我們不難看出:

​随機的startIndex​

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

​nextReplicaShitf:​

​ 盡量讓單個Topic的副本配置設定的更散列一些

分區擴容配置設定方式

分區擴容的情況,也是調用上面的方法,配置設定規則都是一樣的; 但是入參卻又有一些不一樣

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

這個bug,你中招了嗎?

最終也是調用了​

​AdminUtils.assignReplicasToBrokers​

​方法; 但是入參有些不同

  1. ​Broker List​

    ​ 是

    allBrokers

    ; 這裡

    allBrokers

    是從下面方法裡擷取的,從zk裡面拿到Brokers節點再進行排序之後的清單; 如{0,1,2,3,4,5}
  2. 這個bug,你中招了嗎?
  3. ​startIndex:​

    ​ 在這裡并不是一個随機值了,而是

    existingAssignmentPartition0.head

    擷取的值; 這個表示的是目前Topic的第一個分區的第一個副本 在

    Brokerlist

    中的索引值;
  4. ​nextReplicaShitf:​

    ​ 這裡跟

    startIndex

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

    startIndex

    nextReplicaShitf:

    跟它一樣,如下圖代碼
  5. 這個bug,你中招了嗎?
  6. ​startPartitionId:​

    ​ 這裡的值是已經存在的分區數; 建立topic的時候這個值是0; [圖檔上傳失敗...(image-522218-1669001591923)]
那麼那麼把上面建立的t2(10分區,3副本), 執行一下分區擴容,擴容到13個;
這個bug,你中招了嗎?
這個bug,你中招了嗎?

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

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

這個bug,你中招了嗎?

擴分區到5個,新增的分區配置設定如下

這個bug,你中招了嗎?

配置設定圖

這個bug,你中招了嗎?

如果要均衡配置設定的話,至少是 1、1、1、1、1 才算是均衡,現在是直接有一個Broker沒有用上了;

為什麼會出現這種情況?

我們先分析一下 寫這段代碼的人想做什麼?

上圖左邊是最終擴容之後的配置設定,右邊是擴容時候的計算方式; 從上我們可以分析得出

  1. 分區擴容不會變更之前的配置設定情況,隻會變更重新計算擴容的那部分分區的配置設定規則;
  2. ​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萬字長文嘔心瀝血教你徹底搞懂資料遷移原理(附配套教學視訊)

這裡就不再贅述了,直接抛出結果;

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

這個bug,你中招了嗎?

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

​--generate​

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

​startIndex​

​ 和 ​

​nextReplicaShift​

​ 都還是随機的;

至少重新配置設定之後, 分區是均衡的了

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

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

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

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

再往上

這個bug,你中招了嗎?
這個bug,你中招了嗎?
這個bug,你中招了嗎?
  1. 先排序了!!!
  2. 然後通過這個BrokerID又去zk擷取每個Broker的具體資訊
  3. 傳回結果最終 ​

    ​toMap​

    ​ 了放到Map對象去了,是以這也就是為什麼不是有序的原因了;

總結

  1. 現有的情況,在擴分區的時候有可能會造成分區配置設定不均勻的情況
  2. 「 Topic建立 」的時候沒有排序,可是「 擴分區」 、「 重配置設定 」 卻又是排序了
  3. 「 Topic建立 」的時候沒有排序,可是「 擴分區」的時候,它的計算邏輯是按照原有的配置設定方式就是順序的
  4. 如果建立的時候是順序的,那麼「 擴分區」造成配置設定不均勻的情況就不會出現
  5. 「 Topic建立 」的時候,它先是排序了,可是最後卻放到Map裡面了,如果它不是最終想排序,為啥一開始的時候就排序?,因為這裡的排序完全沒有必要;