Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[COST] Inaccurate NetworkCost partition bandwidth estimation with early broker metrics #1641

Open
garyparrot opened this issue Apr 7, 2023 · 42 comments
Milestone

Comments

@garyparrot
Copy link
Collaborator

garyparrot commented Apr 7, 2023

進行 Balancer 實驗時發現 Cost 計算出來的預期叢集狀態和實際搬移下去的結果不一樣,本來 Ingress 的部分應該全部都是一樣的流量,但最終搬移出來的結果是有 5 個節點流量差不多,但 1 個節點和其他節點有 100 MB/s 的流量差異。

經過一些追蹤後發現 NetworkCost 給每個 partition 預估的流量和 Perf 那邊應該要打出去的流量不一致

partition Network Cost 預估的流量(Byte/s) Performance Tool 輸入的流量(Byte/s)
topic_0-0 427865 329198
topic_0-1 55440 50582
topic_0-2 481375 357652
topic_0-3 159400 130012
topic_0-4 346370 271731

基本上每個 partition 都有這樣的現象(而且都是 Network Cost 預估的流量高過 Perf 的流量,而非更低),而 partition 數量有 10000 個,因此整個誤差堆積下來會造成很顯著的影響。

經過一些追蹤後目前懷疑是 Kafka Metrics 的問題:

inacc

這個測試是使用 #1476 的 Backbone Imbalance Scenario,在差不多 Performance Tool 啟動的時候開始追蹤 Kafka Broker 的幾個 MBean 值。

  • 紅線: backbone topic 在特定節點的瞬時流量
  • 綠線: backbone topic 在特定節點的流量 OneMinuteRate
  • 藍線: backbone topic 在特定節點的流量 FifteenMinuteRate

從上圖可以看到,當 Performance Tool 開始動起來的時候,他們的 Rate 是從一個很詭異的高處當做起始值。這感覺和我一開始預期的 Window 取法不太一樣。另外一個問題時他們的 FifteenMinuteRate 花了 15 分鐘以上的時間來收斂到應該的瞬時流量值。本來從名稱來猜測的話他會保留 15 minute 內的流量來做 average,但觀察下來的結果是,這個 window 可能有 50 分鐘的長度(或是他們的 window rate 定義和我想的不太一樣)。

這個行為代表如果 NetworkCost 想要準確的預估每個 partition 的流量,不能夠使用叢集一開始的 metrics,可能需要等一段時間才能採用。

@garyparrot
Copy link
Collaborator Author

我會開一個 PR 讓 NetworkCost 採用的 Rate 能夠被變動,使用 OneMinuteRate 可以讓實驗順利一些。

順便加上一些 Javadoc 提示,NetworkCost 使用上的假設可能要變多

@garyparrot garyparrot changed the title [COST] Inaccurate NetworkCost partition bandwidth estimation [COST] Inaccurate NetworkCost partition bandwidth estimation with early broker metrics Apr 7, 2023
@chia7712
Copy link
Contributor

chia7712 commented Apr 7, 2023

@qoo332001 有機會看一下嗎?你之前有用 ewma 做我們自己的統計工具,可否看看這個現象是否「合理」?

@chia7712
Copy link
Contributor

chia7712 commented Apr 7, 2023

@garyparrot 是否方便把 five minute 也畫上去?看看是不是介於 一分鐘和十五分鐘之間

@garyparrot
Copy link
Collaborator Author

garyparrot commented Apr 7, 2023

是否方便把 five minute 也畫上去?看看是不是介於 一分鐘和十五分鐘之間

是在他們中間沒錯

image

image

@chia7712
Copy link
Contributor

chia7712 commented Apr 7, 2023

是在他們中間沒錯

感謝確認,那計算方式應該是沒錯( 等 @qoo332001 double check),不過不管怎樣,你說加入參數調整參考 one/five/fifteen 是一個可行的方式,所以 +1

@qoo332001
Copy link
Collaborator

@qoo332001 有機會看一下嗎?你之前有用 ewma 做我們自己的統計工具,可否看看這個現象是否「合理」?

剛剛試了一下jmx的統計metrics,確實會有這個現象,可以發現剛開始有流量時,所有統計值都會在一個很高的點,之後再慢慢往下跑
image

後來使用自己的統計邏輯簡單測試一下oneMinuteRate,沒有這個現象
image

@chia7712
Copy link
Contributor

chia7712 commented Apr 8, 2023

@qoo332001 感謝回覆

可否試試看直接使用 yammer 來做統計看看,我們需要釐清問題是出在 yammer 用的演算法,或者是 kafka bug

@qoo332001
Copy link
Collaborator

可否試試看直接使用 yammer 來做統計看看,我們需要釐清問題是出在 yammer 用的演算法,或者是 kafka bug

yammer指的是它預設提供的統計值嗎? 如果是的話第一張圖用的是yammer提供的三種統計值(1min,5min,15min),第二張圖則是我自己紀錄metrics裡面的count,最後在統計出他的成長速度

@chia7712
Copy link
Contributor

chia7712 commented Apr 9, 2023

@qoo332001 感謝回覆,所以這是yammer演算法導致的結果嗎?如果是的話這是符合預期的嗎?

@qoo332001
Copy link
Collaborator

所以這是yammer演算法導致的結果嗎?

看起來是的,上圖是紀錄叢集從沒流量到有流量,要是正常計算平均值的話(也將前面的0算進去),不應該是從一個奇怪的高點開始往下跑,而第二張圖自己做統計就沒有這樣的情況發生

@chia7712
Copy link
Contributor

chia7712 commented Apr 9, 2023

看起來是的,上圖是紀錄叢集從沒流量到有流量

請問可否試著去看一下 yammer 的實作(原始碼)來確定這個問題?

@qoo332001
Copy link
Collaborator

請問可否試著去看一下 yammer 的實作(原始碼)來確定這個問題?

看了一下原始碼可以發現它統計其實是使用指數移動平均來做統計,也就是時間愈近的資料加權會愈重,也就是瞬間有資料進來時,當下統計到的流量*權重會是最大的

簡單改了一下自己的統計邏輯,改成使用指數移動平均來統計(專案的Avg.expWeightByTime()),在跑一次測試:
image

對比使用一般的平均算法(專案的Avg.of()):
image

可以明顯看出使用指數移動平均明顯會有一開始算出來的值明顯比較高的情況

@chia7712
Copy link
Contributor

改成使用指數移動平均來統計(專案的Avg.expWeightByTime()),在跑一次測試:

可是這張圖的趨勢和yammer還是不太一樣,是吧?yammer是從高點趨近於穩定,你貼的這張圖是從低點趨近於穩定

@qoo332001
Copy link
Collaborator

你貼的這張圖是從低點趨近於穩定

重新看了一下yammer的實做,可以發現它有特別處理第一個進來的資料,簡單來說,yammer的實做在沒有資料可以參考時,會把第一筆資料當成過去 1/5/15 min的平均值,但我自己實做的EWMA工具在沒有資料參考時,還是會用0來做統計,所以才會有這樣的差異出現,改一下自己的EWMA工具,改成與yammer一樣,沒資料時就不去做統計,可以發現出來的曲線與yammer算出來的很相似

image

@garyparrot
Copy link
Collaborator Author

garyparrot commented Apr 10, 2023

Performance Tool 剛跑起來的時候會吐入大量的資料。

image

像是上圖所示,一開始的時候會吐入比較大量的資料

image

回顧這個 Issue 一開始的測量圖,也可以看到剛開始時該 Partition 的瞬時流量有比較高 (spike)

這可能是 JVM 的 Hotspot 天性所致,一開始的時候會跑比較慢,所以資料會稍微堆積,等後面程式碼暖了傳輸順了,這個現象就沒有了。

然後猜測是 Kafka 使用的 Yammer 看到 Partition 一開始的高流量,然後就拿這個流量當做 @qoo332001 提到的起始值。但實際上這個高流量只是暫時的現象,很快等一下就會掉下來,然後 5/15 minute rate 的 EWMA 對新的 measure value 的權重沒有那麼高,這會需要比較長來把這個高流量的初始值蓋掉 ,所以這個短暫的高流量才會造成那麼長遠的影響。

@chia7712
Copy link
Contributor

然後猜測是 Kafka 使用的 Yammer 看到 Partition 一開始的高流量,然後就拿這個流量當做 @qoo332001 提到的起始值。但實際上這個高流量只是暫時的現象,很快等一下就會掉下來,然後 5/15 minute rate 的 EWMA 對新的 measure value 的權重沒有那麼高,這會需要比較長來把這個高流量的初始值蓋掉 ,所以這個短暫的高流量才會造成那麼長遠的影響。

@garyparrot @qoo332001 感謝你們的分析和回覆,我覺得講得很好。延伸下去:你們覺得這是一個 bug 嗎?

@garyparrot
Copy link
Collaborator Author

garyparrot commented May 20, 2023

感謝你們的分析和回覆,我覺得講得很好。延伸下去:你們覺得這是一個 bug 嗎?

EWMA 沒有指定初始值要設多少,這邊的做法是拿第一個看到的數字當做初始值。其實這樣做也不能說不對,單純做法差異,所以這不是 bug,只是他們的實作細節導致這樣的行為,然後這個行為在我們的情境中很難用。

我看了一下裡面的實作附上的文獻資料,看起來他們的 fifteen minute rate 數字有這種含義,現在的值 X(t) 中,有 1/e 會貢獻自 X(t - 15分鐘)。所以理論上 15 分鐘 Rate 是指說,15 分鐘前的歷史數據將會佔據現在的 X(t) 大約 36% 的比例。36% 這個數字其實不小,所以才會衍生這個議題觀測到的情況:15 分鐘後這個數字還是沒有收斂到現在的固定速度。我原先預期他會是一種 Simple Window Average,也就是 15 分鐘之前的歷史數據佔據 0% 的比例。

我最後的想法是這個數字其實非常的 summary,他只反映過去大量數據的一個趨勢,他在這些情況的時候會便得沒有參考價值:

  • 過去的數據量不夠多的時候(要讓初始值的影響降到 0.67%,OneMinuteRate 要 5 分鐘,FiveMinuteRate 要 25 分鐘,FifteenMinuteRate 要 75 分鐘)。
  • 過去的趨勢變動非常頻繁的時候。
  • 我們很關心瞬時的流量行為的時候。

目前應該是沒有需要分析瞬時流量的需求,所以我想沒有程式碼變動的必要,不過上面有一個結論應該可以加到 NetworkCost 的使用假設,就是使用 OneMinuteRate 的時候,記得叢集要先開機跑可能 5 分鐘,不然負載平衡的結果可能會不理想。

@chia7712
Copy link
Contributor

就是使用 OneMinuteRate 的時候,記得叢集要先開機跑可能 5 分鐘,不然負載平衡的結果可能會不理想。

這個結論有辦法「放到程式碼」裡面嗎?

例如我們要有一個方式「捕捉」到這個現象,並且給予「特定的錯誤資訊」讓使用者可以意識到這個「限制」

@chia7712
Copy link
Contributor

15 分鐘前的歷史數據將會佔據現在的 X(t) 大約 36% 的比例。

@qoo332001 我們自己的metrics 也有這個現象嗎?

@garyparrot
Copy link
Collaborator Author

這個結論有辦法「放到程式碼」裡面嗎?
例如我們要有一個方式「捕捉」到這個現象,並且給予「特定的錯誤資訊」讓使用者可以意識到這個「限制」

我有一個想法,可以避免掉這個限制,或是說讓這個限制變成一個 feature。

現在是從 BrokerTopic 的流量去逆推 TopicPartition 的流量,然後這個數字是 EWMA 所以會有上面提到的問題。現在改成從 LogSize 去逆推每個時間的瞬時流量( issue 原圖的紅色那條線),這個得到的數字是沒有經過加工處理的 raw data,沒有上面提到的 EWMA 問題。然後我們可以開一個新參數讓使用者去指定,LogSize 至少要累計多長的時間,才能夠視為有足夠的資訊判斷每個 Partition 的流量,比如預設可以設 1 minute,則 ClusterBean 裡面一定要有至少 1 minute 長度的 LogSize 才能夠進行負載平衡。有了這個 1 minute 的 raw data 我們可以在上面做任何我們想做的處理,比如 EWMA 或 Simple Window Average 都行。

其實這個方法很早以前就有想過了,不過那時候礙於一些障礙所以沒辦法實踐,但現在那些障礙我都有想到解決辦法。

@chia7712
Copy link
Contributor

@garyparrot 這個方法聽起來可行,不過就變成我們要捨棄 kafka 已經做好的統計,改成我們自己去統計這些資訊

其實這個方法很早以前就有想過了,不過那時候礙於一些障礙所以沒辦法實踐,但現在那些障礙我都有想到解決辦法。

可否先分享一下「可能的障礙」是什麼?

@garyparrot
Copy link
Collaborator Author

可否先分享一下「可能的障礙」是什麼?

障礙有兩個:

  • LogSize 的流量可能是 Produce + Reassignment。
    • 問題:LogSize 的流量反映的是底下的 Log 在檔案系統的大小,然後我們從檔案大小的變化去得知 Produce 的速度,但這個速度不一定都是 Produce 造成的,如果有發生負載平衡,如 Reassignment 的話我們可能會觀察到非 Client Produce 的寫入速度。這個可能會造成後面計算流量上的誤會。
    • 解決方法:我們用 ReplicaManager 裡面的某個 metrics 是去判斷目前節點身上的 log 是 leader 或 follower,然後我們只使用 leader 的 LogSize 變化當做 Produce 速度。這個做法可以避免上述的問題,因為 Leader 一定必須是 In-Sync-Replica,而 Reassign 進行中的 Log 不會是 In-Sync-Replica,所以透過這個簡單的判斷就可以把 Reassignment 的流量排除。
    • 其他潛在問題:我不確定 Folder 之間的移動,他的 log metrics 會怎麽變化,這邊可能要再觀察一下,如果是單純那個節點會在那個時間有兩個 log size metrics 的話,可以額外偵測這個情況,然後拋棄這個時段的 metrics。
  • LogSize 沒辦法看到 Consumer 的流量
    • 問題:一個 Topic 可以被多個 Consumer 消費,這個時候他的流量會是一個 Produce 流量的一個倍數,然後 LogSize 只能夠反映 Produce 流量,沒辦法反映 Consume 流量。
    • 解決方法:目前是使用 BrokerTopic 流量來得知 Consume 流量,可以繼續用這個速度來 Consumer 流量 / Produce 流量,以得知 Consumer Fanout 的大小數字,有了這個數字,用它乘上 LogSize 推出的 Produce 瞬時流量,最後得到的大概就是 Consume 瞬時流量,這個做法可能會稍微不太精確,但我們也沒有更好的方案來推估 Consume 流量...

@chia7712
Copy link
Contributor

@garyparrot @qoo332001 不好意思,我想回頭討論一下這個議題的「成因」

這個故事是來自於 yammer 的實作會導致「初期」的統計值「震盪」劇烈,這樣講對嗎?

如果上述是對的話,那麼我們可否「偵測」到該現象,並且透過拋出例外來避免我們在這個尷尬的狀態下做balance?

@garyparrot
Copy link
Collaborator Author

這個故事是來自於 yammer 的實作會導致「初期」的統計值「震盪」劇烈,這樣講對嗎?

大致上正確,更精確的說法是起始的統計值選得不好

那麼我們可否「偵測」到該現象,並且透過拋出例外來避免我們在這個尷尬的狀態下做balance?

我想到的方法是看 ClusterBean 裡面有沒有 x 分鐘前到現在連續的 metrics,但這個在目前的實驗機制很難做到,或做到了,會衍生很多副作用,導致使用者覺得我們這個軟體很難用。

@chia7712
Copy link
Contributor

我想到的方法是看 ClusterBean 裡面有沒有 x 分鐘前到現在連續的 metrics,但這個在目前的實驗機制很難做到,或做到了,會衍生很多副作用,導致使用者覺得我們這個軟體很難用。

副作用目前我想到是「必須等到metrics穩定」後才可以跑 balance,你還有想到其他副作用嗎?

@garyparrot
Copy link
Collaborator Author

你還有想到其他副作用嗎?

如果使用者不希望每次 Balance 前要等 metrics 穩定,那他基本上會需要使用遠端版本的 MetricStore。
我對穩定的定義是指等 ClusterBean 裡面有連續 5 分鐘(for OneMinuteRate) 的 metrics。如果是 FifteenMinuteRate 的話要等 75 分鐘,預設的 MetricStore 參數會保留 60 分鐘的 metrics,這可能導致 ClusterBean 裡面的資訊一直做不了負載平衡。

原本想到另外一個問題是 ClusterInfoSensor 有點慢,不過這個問題剛剛開 PR 修正了。

@chia7712
Copy link
Contributor

我對穩定的定義是指等 ClusterBean 裡面有連續 5 分鐘(for OneMinuteRate) 的 metrics

不好意思,這句話我比較看不懂,為何要有“連續”“五分鐘“這兩個條件?我能理解的部分是需要等待一段時間讓 metrics 的“統計”值夠客觀

@garyparrot
Copy link
Collaborator Author

我能理解的部分是需要等待一段時間讓 metrics 的“統計”值夠客觀

具體你覺得要等多久

@garyparrot
Copy link
Collaborator Author

為何要有“連續”“五分鐘“這兩個條件?

數學演算的結果是5分鐘後,初始值的影響會降到 0.67%,然後因為怕這段時間有節點下線上線指標重新統計,要等連續一段時間

@chia7712
Copy link
Contributor

具體你覺得要等多久

我沒特別去想這個,是看到你提到五分鐘所以想先知道你的看法

數學演算的結果是5分鐘後,初始值的影響會降到 0.67%,然後因為怕這段時間有節點下線上線指標重新統計,要等連續一段時間

這樣聽起來蠻合理的。不過大部分的叢集要先跑個五分鐘應該不是啥大問題,所以如果採取“先等個x分鐘“這個方案的話應該是可行的?或者說現在討論的”問題“其實是比較容易發生在我們做實驗的時候,因為我們都是開新叢集灌新資料然後馬上跑測試?

@garyparrot
Copy link
Collaborator Author

這樣聽起來蠻合理的。不過大部分的叢集要先跑個五分鐘應該不是啥大問題,所以如果採取“先等個x分鐘“這個方案的話應該是可行的?或者說現在討論的”問題“其實是比較容易發生在我們做實驗的時候,因為我們都是開新叢集灌新資料然後馬上跑測試?

詳細的等待時間

  • OneMinuteRate 要等 5 分鐘以讓初始值影響降到 0.67%
  • FiveMinuteRate 要等 25 分鐘以讓初始值影響降到 0.67%
  • FifteenMinuteRate 要等 75 分鐘以讓初始值影響降到 0.67%

要這樣做也行,只是這樣會讓 Local Metric Store 越來越難用,走上這條路之後基本上等同於在鼓勵使用長期撈取的 Metric Store,不過這個可能也是無法避免的,因為分析網路流量會需要比較多的資訊,如果大家都同意的話那就這樣執行。

off topic: 我記得好幾個月或一年前的一次和 Metric 有關的討論結果是,我們要儘量避免這種長期儲存效能資訊的行為。不過現在看起來我們要走上這條路。我現在聯想到的其他問題是我們打算讓 ClusterBean 儲存多久的資料,看上面的做法我們可會需要存 75 分鐘以上的 metrics,以後會不會需要讓 ClusterBean 放入整個月或整個禮拜的 metrics

@chia7712
Copy link
Contributor

我記得好幾個月或一年前的一次和 Metric 有關的討論結果是,我們要儘量避免這種長期儲存效能資訊的行為

這句話更完整應該是說“我們的設計必須有一定量的功能是在低複雜度(也就是local metric store) 下就能使用“,並不是說”全部”的功能都只要遵守。如果今天這個 cost 在物理意義上無法配合 local metrics,那就是走我們另一個使用情境,這是沒問題的

看上面的做法我們可會需要存 75 分鐘以上的 metrics,以後會不會需要讓 ClusterBean 放入整個月或整個禮拜的 metrics

這裡我有另一個疑問,等多久 和 我們要存多久 這應該是兩件事情吧?FifteenMinuteRate等75分鐘後 kafka 端拉回來的指標應該就會降低初始值的影響了,所以我們並不需要真的存75分鐘的資料在本地 (or remote),對吧?

@garyparrot
Copy link
Collaborator Author

等多久 和 我們要存多久 這應該是兩件事情吧?FifteenMinuteRate等75分鐘後 kafka 端拉回來的指標應該就會降低初始值的影響了,所以我們並不需要真的存75分鐘的資料在本地 (or remote),對吧?

我想到得知節點已經連續啟動 75 分種的方法是,看 ClusterBean 裡面有沒有連續 75 分鐘的 metric,如果不這樣做,
要如何讓 NetworkCost 知道現在的 metrics 是源自已經啟動 75 分鐘的節點?

我看你的敘述好像是打算在 NetworkCost 的 metric sensor 裡面睡 75 分鐘再做撈取。

@chia7712
Copy link
Contributor

我看你的敘述好像是打算在 NetworkCost 的 metric sensor 裡面睡 75 分鐘再做撈取。

不是的,我的意思能「辨識」這個指標是否已經沒有被影響,也就是已經過了起始那段時間,所以:
1)不用存下來,讓kafka幫我們算就好
2)不用一定要睡75分鐘只要確認現在的指標已經脫離不穩定的狀態

滿足上述network cost就可以開始計算

@garyparrot
Copy link
Collaborator Author

只要確認現在的指標已經脫離不穩定的狀態

噢噢,我懂你的億思了,聽起來沒問題,最後就看要怎麼判斷他進入穩定的狀態

@chia7712
Copy link
Contributor

最後就看要怎麼判斷他進入穩定的狀態

沒錯,你講到重點!我的直覺是類似你之前做的debunce 的邏輯,確認一小段時間的數值變化:

  1. 超過範圍則視為不穩定
  2. 範圍內則通過
  3. 完全沒動則視為沒有流量

@garyparrot 你覺得呢

@qoo332001
Copy link
Collaborator

qoo332001 commented May 22, 2023

@qoo332001 我們自己的metrics 也有這個現象嗎?

如果是我之前自己寫的統計邏輯,可以在統計區間不夠大的時候拋Exception,也就是在metrics不足的時候就不去做統計,避免發生這樣的狀況

@garyparrot
Copy link
Collaborator Author

@garyparrot 你覺得呢

稍微離題,我剛剛發現目前的統計計算方法,在現在的討論討論範圍之外存在一些嚴重的問題

目前的統計方法是去看 BrokerTopic 的流量,這個是 topic 一部分的 partitions 的流量合,因為目前假設每個 partition 流入的流量都是常數,所以每個 partition 的流量會以某個比例反映在 log size 之上,之後我們再用 log size 從 BrokerTopic 的流量去反推每個 partition 的比例。但如果有使用 retention.bytes 的話,這個 log size 的大小可能不太會去和 partition 的流入速度產生關係,進而造成預估上的不準確。

這個是我在使用 retention.bytes 做實驗時發現的問題,計劃產生出一個很接近 0 的計劃,預計可以把流量弄很平,但實際上搬移完後沒有那麼平,這個是很典型的 NetworkCost 預估錯誤現象,我從數據上有觀察到大約 50 MB/s 的預估不準確。

NetworkCost 預估速度: 132396528 Bytes/s
Producer JMX 上統計的速度: 174263002 Bytes/s

@chia7712
Copy link
Contributor

目前的統計方法是去看 BrokerTopic 的流量,這個是 topic 一部分的 partitions 的流量合,因為目前假設每個 partition 流入的流量都是常數,所以每個 partition 的流量會以某個比例反映在 log size 之上,之後我們再用 log size 從 BrokerTopic 的流量去反推每個 partition 的比例。但如果有使用 retention.bytes 的話,這個 log size 的大小可能不太會去和 partition 的流入速度產生關係,進而造成預估上的不準確。

感謝回報,這的確是一個需要討論的議題。不過依照 kafka 背景清理資料的邏輯來看,我們在計算“平均流量”時當好撞到 retention 的機率很高嗎 (預設檢查 retention 的週期是五分鐘一次) ?

另外從 partition size 去推估 partition-level 的流量的確會遇到各種“資料量並非穩定成長”的議題,因此我想像中是在取樣的時候要盡可能“跳過“資料變動的時段,你覺得這樣有可能嗎?

@garyparrot
Copy link
Collaborator Author

garyparrot commented Jun 12, 2023

感謝回報,這的確是一個需要討論的議題。不過依照 kafka 背景清理資料的邏輯來看,我們在計算“平均流量”時當好撞到 retention 的機率很高嗎 (預設檢查 retention 的週期是五分鐘一次) ?

我目前觀察到的不準確的時機並非 retention 發生的那個時刻,而是第一次 retention 後的所有時刻。
目前是直接拿 size 本身來預估,所以會遇到比較嚴重的影響,比如有 zipfian key 分佈的 topic,他的每個 partition 輸入的流量會不太一樣,如果現在 retention 是 x Byte,在長遠的時間後每個 partition 的大小大概是 (x + zipfian下該partition分到的資料量)。如果這個時候 x 很小的話,影響會還好,但通常 x 會很大,造成很大幅度的偏移,比如

  • retention size = 100 GB
  • PartitionA 流入 100 MB/s,五分鐘可以累積 30 GB
  • PartitoinB 流入 10 MB/s,五分鐘可以累積 3 GB
  • PartitionC 流入 1 MB/s,五分鐘可以累積 0.3 GB
  • 叢集跑了很久, A,B,C 的大小都卡在 100 GB 那邊
  • 整體流量 111 MB/s

如果在大家一起 retention 的前一刻做預估,預估結果是

  • PartitionA = 111 * (130) / (130 + 103 + 100.3) = 43 MB/s,比實際少了 57 MB/s
  • PartitionB = 111 * (103) / (130 + 103 + 100.3) = 34 MB/s,比實際多了 24 MB/s
  • PartitionC = 111 * (100.3) / (130 + 103 + 100.3) = 33 MB/s,比實際多了 32 MB/s

我們在計算“平均流量”時當好撞到 retention 的機率很高嗎 (預設檢查 retention 的週期是五分鐘一次) ?

目前是直接用純一個時段的 Size 去當權重,我在想你是不是覺得目前是用 (這個時刻的Size - 上個時刻的Size) / (經過時間) 當做權重,這個是用瞬時流量當權重,可能不會有上面的 x 很大時造成權重偏移的問題,不過用瞬時流量的問題是可能不穩定,但目前的取樣都是好幾秒的間隔,所以其實也不會瞬時到哪裡,或許影響還好。

另外從 partition size 去推估 partition-level 的流量的確會遇到各種“資料量並非穩定成長”的議題,因此我想像中是在取樣的時候要盡可能“跳過“資料變動的時段,你覺得這樣有可能嗎?

這樣做的話可能要比較 t0, t1, t2, t3 的 size 來確定有沒有觸發 retention,如果有變小的跡象,那就是有觸發了

那感覺可以這樣做:

  • 一樣用 BrokerTopic 去逆推 partition 的流量
  • 現在是用 size 的權重,改用 (size1 - size0) / (t1 - t0) 當做權重。
  • 如果 t1, t0 之間有 size 變小的情況,不要採用這段的數據

@garyparrot
Copy link
Collaborator Author

garyparrot commented Jun 12, 2023

NetworkCost 運作會需要得知每個 Partition 的流量用量,目前 NetworkCost 透過 BrokerTopic metric 取得整個 Topic 的流量,這個 Topic 流量會是整個 Broker 上 Partition 的流量之合 X,NetworkCost 需要一個方法來得知每個 Partition a,b,c 的流量在這個 BrokerTopic metric 中的權重比例 Wa, Wb, Wc 各是多少,有了這個權重比例就能逆推出未知的 Partition 流量 a,b,c

  • a = X * (Wa) / (Wa + Wb + Wc)
  • b = X * (Wb) / (Wa + Wb + Wc)
  • c = X * (Wc) / (Wa + Wb + Wc)

現在的計算方式是用 log size 來當做權重,如果每個 Producer 寫入資料的速度不變,則每個 log size 會是各自 write_speed * time,這個數字可以被拿來當做權重使用。但在 retention.bytes 設定的影響下, 當 log 超過一個大小,就會有資料被刪除,因此有套用這個設定的 topic,他底下的 partition 大小都會被控制在一個值之下,在這個情況下,log size 的大小就不會是單純的 write_speed * times,因為沒有維持這個關係所以拿來當權重估計用會出現很嚴重的誤差。

現在提出改進做法是透過 log size 的變化量 (size1 - size0) / (t1 - t0) 來當作權重

其計算等同於 ((write_speed * (t1 - t0) + size0) - size0) / (t1 - t0)
等於 (write_speed * (t1 - t0)) / (t1 - t0)
等於 write_speed

這個數字也是會和我們想要知道的比例呈現直接關係,所以適合拿來當做權重。不過他一樣會遇到 retention 的問題,如果 retention 觸發於 t1 和 t0 之間,則他的 size1 將會是一個刪除過資料且小於 size0 的值,因此整個計算出來的權重會是負數,不過這個問題沒有上面直覺用 log size 那麼嚴重,因為 log size 的影響是長久的,但 log size 變化量只有觸發的那個計算窗會出現這種負數現象,我們可以在遇到這種現象時捨棄該次的計算結果,由於 retention實務上是一個不會經常觸發的行為,因此這個丟棄等下一次的結果在實務上可以被接受。

另外一個問題是 partition 可以有副本,因此整個叢集內會有多個 partition 的 logs,在這個情況下會衍生一個議題是我們要用哪個 log 當做計算的依據,這個部分必須要採用是 leader 身份的那個 log,follower 的 log 不適合的原因是因為 follower 可能處於 insync 狀態,這個時候的流量將會是節點複製資料的流量,而非應用端寫入流量的速度,另外一個 follower log 可能是 reassignment 進行中 log,這個時候的流量也不會是來自應用端的寫入流量速度。因為只有 leader 身份的 log 可以被 client 寫入,因此可以很合理的認為他的 log 大小增加都是源自於 Producer 的寫入。 (@chia7712 這段線下討論的時候我沒有想到)

所以整體來說可以這樣對 NetworkCost 進行修改,以迴避目前的問題

  • 繼續用 BrokerTopic 和權重來計算 Partition 流量
  • 權重統計方法採用 (size1 - size0) / (t1 - t0)
  • 權重取自 leader log
  • 當權重出現負數時,不要使用這個權重計算結果

@chia7712
Copy link
Contributor

因為只有 leader 身份的 log 可以被 client 寫入,因此可以很合理的認為他的 log 大小增加都是源自於 Producer 的寫入。

這個推斷合理 +1

所以整體來說可以這樣對 NetworkCost 進行修改,以迴避目前的問題
繼續用 BrokerTopic 和權重來計算 Partition 流量
權重統計方法採用 (size1 - size0) / (t1 - t0)
權重取自 leader log
當權重出現負數時,不要使用這個權重計算結果

這個結論合理 +1

這個議題討論到的改善可以在七月的時候看要如何實作,希望能放到 0.3.0 裡面

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants