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  }