github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/strategy/global.go (about) 1 package strategy 2 3 import ( 4 "container/heap" 5 "context" 6 7 "github.com/cockroachdb/errors" 8 "github.com/projecteru2/core/log" 9 "github.com/projecteru2/core/types" 10 ) 11 12 type infoHeapForGlobalStrategy []Info 13 14 // Len . 15 func (r infoHeapForGlobalStrategy) Len() int { 16 return len(r) 17 } 18 19 // Less . 20 func (r infoHeapForGlobalStrategy) Less(i, j int) bool { 21 return (r[i].Usage + r[i].Rate) < (r[j].Usage + r[j].Rate) 22 } 23 24 // Swap . 25 func (r infoHeapForGlobalStrategy) Swap(i, j int) { 26 r[i], r[j] = r[j], r[i] 27 } 28 29 // Push . 30 func (r *infoHeapForGlobalStrategy) Push(x any) { 31 *r = append(*r, x.(Info)) 32 } 33 34 // Pop . 35 func (r *infoHeapForGlobalStrategy) Pop() any { 36 old := *r 37 n := len(old) 38 x := old[n-1] 39 *r = old[:n-1] 40 return x 41 } 42 43 // GlobalPlan 基于全局资源配额 44 // 尽量使得资源消耗平均 45 func GlobalPlan(ctx context.Context, infos []Info, need, total, _ int) (map[string]int, error) { 46 if total < need { 47 return nil, errors.Wrapf(types.ErrInsufficientResource, "need: %d, available: %d", need, total) 48 } 49 strategyInfos := make([]Info, len(infos)) 50 copy(strategyInfos, infos) 51 deployMap := map[string]int{} 52 53 infoHeap := &infoHeapForGlobalStrategy{} 54 for _, info := range strategyInfos { 55 if info.Capacity > 0 { 56 infoHeap.Push(info) 57 } 58 } 59 heap.Init(infoHeap) 60 61 for i := 0; i < need; i++ { 62 if infoHeap.Len() == 0 { 63 return nil, errors.Wrapf(types.ErrInsufficientResource, "need: %d, available: %d", need, i) 64 } 65 infoWithMinUsage := heap.Pop(infoHeap).(Info) 66 deployMap[infoWithMinUsage.Nodename]++ 67 infoWithMinUsage.Usage += infoWithMinUsage.Rate 68 infoWithMinUsage.Capacity-- 69 70 if infoWithMinUsage.Capacity > 0 { 71 heap.Push(infoHeap, infoWithMinUsage) 72 } 73 } 74 75 // 这里 need 一定会为 0 出来,因为 volTotal 保证了一定大于 need 76 // 这里并不需要再次排序了,理论上的排序是基于资源使用率得到的 Deploy 最终方案 77 log.WithFunc("strategy.GlobalPlan").Debugf(ctx, "strategyInfos: %+v", strategyInfos) 78 return deployMap, nil 79 }