Kitex 默認提供了兩種 LoadBalancer(下面簡稱 lb):
Kitex 默認使用的是 WeightedRandom。
顧名思義,這個 lb 使用的是基于權(quán)重的隨機策略,也是 Kitex 的默認策略。
這個 lb 會依據(jù)實例的權(quán)重進行加權(quán)隨機,并保證每個實例分配到的負載和自己的權(quán)重成比例。
如果所有的實例的權(quán)重都一樣,Kitex 針對這個場景做了特殊優(yōu)化,會使用一個純隨機的實現(xiàn),來避免加權(quán)計算的一些額外開銷,所以不需要擔心這個場景下的性能。
一致性哈希主要適用于對上下文(如實例本地緩存)依賴程度高的場景,如希望同一個類型的請求打到同一臺機器,則可使用該負載均衡方法。
如果你不了解什么是一致性哈希,或者不知道帶來的副作用,請勿使用一致性哈希。
如果要使用一致性哈希,可以在初始化 client 的時候傳入 ?client.WithLoadBalancer(loadbalance.NewConsistBalancer(loadbalance.NewConsistentHashOption(keyFunc)))
?
?ConsistentHashOption
?定義如下:
type ConsistentHashOption struct {
GetKey KeyFunc
// 是否使用 replica
// 如果使用,當請求失?。ㄟB接失敗)后會依次嘗試 replica
// 會帶來額外內(nèi)存和計算開銷
// 如果不設(shè)置,那么請求失?。ㄟB接失敗)后直接返回
Replica uint32
// 虛擬節(jié)點數(shù)
// 每個真實節(jié)點對應(yīng)的虛擬節(jié)點的數(shù)量
// 這個數(shù)值越大,內(nèi)存和計算代價越大,負載越均衡
// 當節(jié)點數(shù)多時,可以適當設(shè)小一些;反之可以適當設(shè)大一些
// 推薦 VirtualFactor * Weight(如果 Weighted 為 true)的中位數(shù)在 1000 左右,負載應(yīng)當已經(jīng)很均衡了
// 推薦 總虛擬節(jié)點數(shù) 在 2000W 以內(nèi)(1000W 情況之下 build 一次需要 250ms,不過為后臺 build 理論上 3s 內(nèi)均無問題)
VirtualFactor uint32
// 是否要遵循 Weight 進行負載均衡
// 如果為 false,對于每個 instance 都會忽略 Weight,均生成 VirtualFactor 個虛擬節(jié)點,進行無差別負載均衡
// 如果為 true,對于每個 instance 會生成 instance.Weight() * VirtualFactor 個虛擬節(jié)點
// 需要注意,對于 weight 為 0 的 instance,無論 VirtualFactor 為多少,均不會生成虛擬節(jié)點
// 建議設(shè)為 true,不過要注意適當調(diào)小 VirtualFactor
Weighted bool
// 是否進行過期處理
// 實現(xiàn)會緩存所有的 Key
// 如果永不過期會導(dǎo)致內(nèi)存一直增長
// 設(shè)置過期會導(dǎo)致額外性能開銷
// 目前的實現(xiàn)是每分鐘掃描刪除一次,以及實例發(fā)生變動 rebuild 時刪除一次
// 建議一定要設(shè)置,值不要小于一分鐘
ExpireDuration time.Duration
}
要注意,如果 GetKey 是 nil 或者 VirtualFactor 是 0,會 panic。
經(jīng)過測試,在 weight 為 10、VirtualFactor 為 100 的情況之下,不同 instance 數(shù)量的 build 性能如下:
BenchmarkNewConsistPicker_NoCache/10ins-16 6565 160670 ns/op 164750 B/op 5 allocs/op
BenchmarkNewConsistPicker_NoCache/100ins-16 571 1914666 ns/op 1611803 B/op 6 allocs/op
BenchmarkNewConsistPicker_NoCache/1000ins-16 45 23485916 ns/op 16067720 B/op 10 allocs/op
BenchmarkNewConsistPicker_NoCache/10000ins-16 4 251160920 ns/op 160405632 B/op 41 allocs/op
所以當有 10000 個 instance,每個 instance weight 為 10,VirtualFactor 為 100 的情況之下(總虛擬節(jié)點數(shù) 1000W),build 一次需要 251 ms。
build 和 請求 信息都會被緩存,所以一次正常請求(不需要 build)的時延和節(jié)點多少無關(guān),如下:
BenchmarkNewConsistPicker/10ins-16 12557137 81.1 ns/op 0 B/op 0 allocs/op
BenchmarkNewConsistPicker/100ins-16 13704381 82.3 ns/op 0 B/op 0 allocs/op
BenchmarkNewConsistPicker/1000ins-16 14418103 81.3 ns/op 0 B/op 0 allocs/op
BenchmarkNewConsistPicker/10000ins-16 13942186 81.0 ns/op 0 B/op 0 allocs/op
注意事項
經(jīng)過測試,當下游實例為 10 個時,如果 VirtualFactor 設(shè)置為 1 并且不開啟 Weighted 時,負載非常不均衡,如下:
addr2: 28629
addr7: 13489
addr3: 10469
addr9: 4554
addr0: 21550
addr6: 6516
addr8: 2354
addr4: 9413
addr5: 1793
addr1: 1233
當 VirtualFactor 設(shè)置為 10 時,負載如下:
addr7: 14426
addr8: 12469
addr3: 8115
addr4: 8165
addr0: 8587
addr1: 7193
addr6: 10512
addr9: 14054
addr2: 9307
addr5: 7172
可以看出比 VirtualFactor 為 1 時要好很多。
當 VirtualFactor 為 1000 時,負載如下:
addr7: 9697
addr5: 9933
addr6: 9955
addr4: 10361
addr8: 9828
addr0: 9729
addr9: 10528
addr2: 10121
addr3: 9888
addr1: 9960
可以看出此時負載基本均衡。
再來看看帶 Weight 的情況,我們設(shè)置 addr0 的 weight 為 0,addr1 的 weight 為 1,addr2 的 weight 為 2……以此類推。
設(shè)置 VirtualFactor 為 1000,得到負載結(jié)果如下:
addr4: 8839
addr3: 6624
addr6: 13250
addr1: 2318
addr8: 17769
addr2: 4321
addr5: 11099
addr9: 20065
addr7: 15715
可以看到基本是和 weight 的分布一致。在這里沒有 addr0 是因為 weight 為 0 是不會被調(diào)度到的。
綜上,提高 VirtualFactor,可以使得負載更加均衡,但是也要注意會增加性能開銷,需要找個平衡點。
更多建議: