gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/grpc/balancer/weightedtarget/weightedtarget.go (about) 1 /* 2 * 3 * Copyright 2020 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package weightedtarget implements the weighted_target balancer. 20 // 21 // All APIs in this package are experimental. 22 package weightedtarget 23 24 import ( 25 "encoding/json" 26 "fmt" 27 28 "gitee.com/zhaochuninhefei/gmgo/grpc/balancer" 29 "gitee.com/zhaochuninhefei/gmgo/grpc/balancer/weightedtarget/weightedaggregator" 30 "gitee.com/zhaochuninhefei/gmgo/grpc/internal/balancergroup" 31 "gitee.com/zhaochuninhefei/gmgo/grpc/internal/grpclog" 32 "gitee.com/zhaochuninhefei/gmgo/grpc/internal/hierarchy" 33 "gitee.com/zhaochuninhefei/gmgo/grpc/internal/pretty" 34 "gitee.com/zhaochuninhefei/gmgo/grpc/internal/wrr" 35 "gitee.com/zhaochuninhefei/gmgo/grpc/resolver" 36 "gitee.com/zhaochuninhefei/gmgo/grpc/serviceconfig" 37 ) 38 39 // Name is the name of the weighted_target balancer. 40 const Name = "weighted_target_experimental" 41 42 // NewRandomWRR is the WRR constructor used to pick sub-pickers from 43 // sub-balancers. It's to be modified in tests. 44 var NewRandomWRR = wrr.NewRandom 45 46 func init() { 47 balancer.Register(bb{}) 48 } 49 50 type bb struct{} 51 52 func (bb) Build(cc balancer.ClientConn, bOpts balancer.BuildOptions) balancer.Balancer { 53 b := &weightedTargetBalancer{} 54 b.logger = prefixLogger(b) 55 b.stateAggregator = weightedaggregator.New(cc, b.logger, NewRandomWRR) 56 b.stateAggregator.Start() 57 b.bg = balancergroup.New(cc, bOpts, b.stateAggregator, b.logger) 58 b.bg.Start() 59 b.logger.Infof("Created") 60 return b 61 } 62 63 func (bb) Name() string { 64 return Name 65 } 66 67 func (bb) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { 68 return parseConfig(c) 69 } 70 71 type weightedTargetBalancer struct { 72 logger *grpclog.PrefixLogger 73 74 bg *balancergroup.BalancerGroup 75 stateAggregator *weightedaggregator.Aggregator 76 77 targets map[string]Target 78 } 79 80 // UpdateClientConnState takes the new targets in balancer group, 81 // creates/deletes sub-balancers and sends them update. addresses are split into 82 // groups based on hierarchy path. 83 func (b *weightedTargetBalancer) UpdateClientConnState(s balancer.ClientConnState) error { 84 b.logger.Infof("Received update from resolver, balancer config: %+v", pretty.ToJSON(s.BalancerConfig)) 85 newConfig, ok := s.BalancerConfig.(*LBConfig) 86 if !ok { 87 return fmt.Errorf("unexpected balancer config with type: %T", s.BalancerConfig) 88 } 89 addressesSplit := hierarchy.Group(s.ResolverState.Addresses) 90 91 var rebuildStateAndPicker bool 92 93 // Remove sub-pickers and sub-balancers that are not in the new config. 94 for name := range b.targets { 95 if _, ok := newConfig.Targets[name]; !ok { 96 b.stateAggregator.Remove(name) 97 b.bg.Remove(name) 98 // Trigger a state/picker update, because we don't want `ClientConn` 99 // to pick this sub-balancer anymore. 100 rebuildStateAndPicker = true 101 } 102 } 103 104 // For sub-balancers in the new config 105 // - if it's new. add to balancer group, 106 // - if it's old, but has a new weight, update weight in balancer group. 107 // 108 // For all sub-balancers, forward the address/balancer config update. 109 for name, newT := range newConfig.Targets { 110 oldT, ok := b.targets[name] 111 if !ok { 112 // If this is a new sub-balancer, add weights to the picker map. 113 b.stateAggregator.Add(name, newT.Weight) 114 // Then add to the balancer group. 115 b.bg.Add(name, balancer.Get(newT.ChildPolicy.Name)) 116 // Not trigger a state/picker update. Wait for the new sub-balancer 117 // to send its updates. 118 } else if newT.ChildPolicy.Name != oldT.ChildPolicy.Name { 119 // If the child policy name is differet, remove from balancer group 120 // and re-add. 121 b.stateAggregator.Remove(name) 122 b.bg.Remove(name) 123 b.stateAggregator.Add(name, newT.Weight) 124 b.bg.Add(name, balancer.Get(newT.ChildPolicy.Name)) 125 // Trigger a state/picker update, because we don't want `ClientConn` 126 // to pick this sub-balancer anymore. 127 rebuildStateAndPicker = true 128 } else if newT.Weight != oldT.Weight { 129 // If this is an existing sub-balancer, update weight if necessary. 130 b.stateAggregator.UpdateWeight(name, newT.Weight) 131 // Trigger a state/picker update, because we don't want `ClientConn` 132 // should do picks with the new weights now. 133 rebuildStateAndPicker = true 134 } 135 136 // Forwards all the update: 137 // - addresses are from the map after splitting with hierarchy path, 138 // - Top level service config and attributes are the same, 139 // - Balancer config comes from the targets map. 140 // 141 // TODO: handle error? How to aggregate errors and return? 142 _ = b.bg.UpdateClientConnState(name, balancer.ClientConnState{ 143 ResolverState: resolver.State{ 144 Addresses: addressesSplit[name], 145 ServiceConfig: s.ResolverState.ServiceConfig, 146 Attributes: s.ResolverState.Attributes, 147 }, 148 BalancerConfig: newT.ChildPolicy.Config, 149 }) 150 } 151 152 b.targets = newConfig.Targets 153 154 if rebuildStateAndPicker { 155 b.stateAggregator.BuildAndUpdate() 156 } 157 return nil 158 } 159 160 func (b *weightedTargetBalancer) ResolverError(err error) { 161 b.bg.ResolverError(err) 162 } 163 164 func (b *weightedTargetBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { 165 b.bg.UpdateSubConnState(sc, state) 166 } 167 168 func (b *weightedTargetBalancer) Close() { 169 b.stateAggregator.Stop() 170 b.bg.Close() 171 } 172 173 func (b *weightedTargetBalancer) ExitIdle() { 174 b.bg.ExitIdle() 175 }