遊戲陪玩系統實現自適應負載均衡演算法的方式
背景
演算法的核心思想
type PickerBuilder interface { // Build returns a picker that will be used by gRPC to pick a SubConn. Build(info PickerBuildInfo) balancer.Picker}
type Picker interface { Pick(info PickInfo) (PickResult, error)}
type subConn struct { addr resolver.Address conn balancer.SubConn lag uint64 // 用來儲存 ewma 值 inflight int64 // 用在儲存當前節點正在處理的請求總數 success uint64 // 用來標識一段時間內此連線的健康狀態 requests int64 // 用來儲存請求總數 last int64 // 用來儲存上一次請求耗時, 用於計算 ewma 值 pick int64 // 儲存上一次被選中的時間點}
type p2cPicker struct { conns []*subConn // 儲存所有節點的資訊 r *rand.Rand stamp *syncx.AtomicDuration lock sync.Mutex}
func (b *p2cPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker { ...... var conns []*subConn for conn, connInfo := range readySCs { conns = append(conns, &subConn{ addr: connInfo.Address, conn: conn, success: initSuccess, }) } return &p2cPicker{ conns: conns, r: rand.New(rand.NewSource(time.Now().UnixNano())), stamp: syncx.NewAtomicDuration(), }}
switch len(p.conns) { case 0:// 沒有節點,返回錯誤 return emptyPickResult, balancer.ErrNoSubConnAvailable case 1:// 有一個節點,直接返回這個節點 chosen = p.choose(p.conns[0], nil) case 2:// 有兩個節點,計算負載,返回負載低的節點 chosen = p.choose(p.conns[0], p.conns[1]) default:// 有多個節點,p2c 挑選兩個節點,比較這兩個節點的負載,返回負載低的節點 var node1, node2 *subConn // 3次隨機選擇兩個節點 for i := 0; i < pickTimes; i++ { a := p.r.Intn(len(p.conns)) b := p.r.Intn(len(p.conns) - 1) if b >= a { b++ } node1 = p.conns[a] node2 = p.conns[b] // 如果這次選擇的節點達到了健康要求, 就中斷選擇 if node1.healthy() && node2.healthy() { break } } // 比較兩個節點的負載情況,選擇負載低的 chosen = p.choose(node1, node2) }
func (c *subConn) load() int64 { // 通過 EWMA 計算節點的負載情況; 加 1 是為了避免為 0 的情況 lag := int64(math.Sqrt(float64(atomic.LoadUint64(&c.lag) + 1))) load := lag * (atomic.LoadInt64(&c.inflight) + 1) if load == 0 { return penalty } return load}
func (p *p2cPicker) buildDoneFunc(c *subConn) func(info balancer.DoneInfo) { start := int64(timex.Now()) return func(info balancer.DoneInfo) { // 正在處理的請求數減 1 atomic.AddInt64(&c.inflight, -1) now := timex.Now() // 儲存本次請求結束時的時間點,並取出上次請求時的時間點 last := atomic.SwapInt64(&c.last, int64(now)) td := int64(now) - last if td < 0 { td = 0 } // 用牛頓冷卻定律中的衰減函式模型計算EWMA演算法中的β值 w := math.Exp(float64(-td) / float64(decayTime)) // 儲存本次請求的耗時 lag := int64(now) - start if lag < 0 { lag = 0 } olag := atomic.LoadUint64(&c.lag) if olag == 0 { w = 0 } // 計算 EWMA 值 atomic.StoreUint64(&c.lag, uint64(float64(olag)*w+float64(lag)*(1-w))) success := initSuccess if info.Err != nil && !codes.Acceptable(info.Err) { success = 0 } osucc := atomic.LoadUint64(&c.success) atomic.StoreUint64(&c.success, uint64(float64(osucc)*w+float64(success)*(1-w))) stamp := p.stamp.Load() if now-stamp >= logInterval { if p.stamp.CompareAndSwap(stamp, now) { p.logStats() } } }}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2841984/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 自適應負載均衡演算法原理與實現負載演算法
- 遊戲陪玩系統原始碼中不同排序演算法的實現方式遊戲原始碼排序演算法
- 遊戲陪玩系統原始碼中懶載入的實現方式有哪幾種?遊戲原始碼
- 遊戲陪玩原始碼的移動端適配,應該如何實現?遊戲原始碼
- 透過websocket,實現遊戲陪玩系統的聊天室Web遊戲
- 如何實現遊戲陪玩系統原始碼前端效能監控?遊戲原始碼前端
- 超實用:實現負載均衡技術的方式負載
- 六種實現負載均衡技術的方式負載
- 如何實現遊戲陪玩系統中語音的錄製與播放?遊戲
- 遊戲陪玩系統開發,Java怎樣實現流合併?遊戲Java
- 遊戲陪玩系統開發,音視訊混流的實現程式碼遊戲
- 如何在遊戲陪玩系統原始碼中實現“刮刮樂”效果?遊戲原始碼
- 遊戲陪玩系統開發,日期時間選擇介面的實現遊戲
- 帶你瞭解遊戲陪玩系統原始碼前端常用的儲存方式遊戲原始碼前端
- SAP 應用服務負載均衡的實現負載
- 淺談負載均衡演算法與實現負載演算法
- Ribbon實現負載均衡負載
- GRPC 負載均衡實現RPC負載
- nginx實現負載均衡Nginx負載
- 一篇有趣的負載均衡演算法實現負載演算法
- Consul-template+nginx實現自動負載均衡Nginx負載
- Linux下玩轉nginx系列(五)---nginx實現負載均衡LinuxNginx負載
- 遊戲陪玩APP遊戲APP
- 遊戲陪玩原始碼的登入方式,簡訊驗證碼登入的實現遊戲原始碼
- HaProxy 實現 MySQL 負載均衡MySql負載
- 遊戲陪玩系統原始碼開發,如何實現圖片和動畫的優化?遊戲原始碼動畫優化
- 負載均衡的幾種演算法Java實現程式碼負載演算法Java
- 如何在遊戲陪玩系統原始碼中聊天室內實現一個禮物系統?遊戲原始碼
- 解密負載均衡技術和負載均衡演算法解密負載演算法
- 遊戲陪玩系統開發,架構設計的開閉原則是如何實現的?遊戲架構
- Nginx實現簡單的負載均衡Nginx負載
- 【演算法】使用Golang實現加權負載均衡演算法演算法Golang負載
- 遊戲陪玩系統原始碼的許可權設計,如何基於位運算實現?遊戲原始碼
- 如何進行遊戲陪玩系統原始碼中音視訊的自動化測試?遊戲原始碼
- 遊戲陪玩app開發,訊息可靠性的實現遊戲APP
- nginx+tomcat實現負載均衡NginxTomcat負載
- dubbo(三):負載均衡實現解析負載
- 使用YARP來實現負載均衡負載