dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/balancer/clustermanager/clustermanager.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  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   *
    20   * Copyright 2020 gRPC authors.
    21   *
    22   */
    23  
    24  // Package clustermanager implements the cluster manager LB policy for xds.
    25  package clustermanager
    26  
    27  import (
    28  	"encoding/json"
    29  	"fmt"
    30  )
    31  
    32  import (
    33  	dubbogoLogger "github.com/dubbogo/gost/log/logger"
    34  
    35  	"google.golang.org/grpc/balancer"
    36  
    37  	"google.golang.org/grpc/resolver"
    38  
    39  	"google.golang.org/grpc/serviceconfig"
    40  )
    41  
    42  import (
    43  	"dubbo.apache.org/dubbo-go/v3/xds/utils/balancergroup"
    44  	"dubbo.apache.org/dubbo-go/v3/xds/utils/hierarchy"
    45  	"dubbo.apache.org/dubbo-go/v3/xds/utils/pretty"
    46  )
    47  
    48  const balancerName = "xds_cluster_manager_experimental"
    49  
    50  func init() {
    51  	balancer.Register(bb{})
    52  }
    53  
    54  type bb struct{}
    55  
    56  func (bb) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer {
    57  	b := &bal{}
    58  	b.logger = dubbogoLogger.GetLogger()
    59  	b.stateAggregator = newBalancerStateAggregator(cc, b.logger)
    60  	b.stateAggregator.start()
    61  	b.bg = balancergroup.New(cc, opts, b.stateAggregator, b.logger)
    62  	b.bg.Start()
    63  	b.logger.Infof("Created")
    64  	return b
    65  }
    66  
    67  func (bb) Name() string {
    68  	return balancerName
    69  }
    70  
    71  func (bb) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
    72  	return parseConfig(c)
    73  }
    74  
    75  type bal struct {
    76  	logger dubbogoLogger.Logger
    77  
    78  	// TODO: make this package not dependent on xds specific code. Same as for
    79  	// weighted target balancer.
    80  	bg              *balancergroup.BalancerGroup
    81  	stateAggregator *balancerStateAggregator
    82  
    83  	children map[string]childConfig
    84  }
    85  
    86  func (b *bal) updateChildren(s balancer.ClientConnState, newConfig *lbConfig) {
    87  	update := false
    88  	addressesSplit := hierarchy.Group(s.ResolverState.Addresses)
    89  
    90  	// Remove sub-pickers and sub-balancers that are not in the new cluster list.
    91  	for name := range b.children {
    92  		if _, ok := newConfig.Children[name]; !ok {
    93  			b.stateAggregator.remove(name)
    94  			b.bg.Remove(name)
    95  			update = true
    96  		}
    97  	}
    98  
    99  	// For sub-balancers in the new cluster list,
   100  	// - add to balancer group if it's new,
   101  	// - forward the address/balancer config update.
   102  	for name, newT := range newConfig.Children {
   103  		if _, ok := b.children[name]; !ok {
   104  			// If this is a new sub-balancer, add it to the picker map.
   105  			b.stateAggregator.add(name)
   106  			// Then add to the balancer group.
   107  			b.bg.Add(name, balancer.Get(newT.ChildPolicy.Name))
   108  		}
   109  		// TODO: handle error? How to aggregate errors and return?
   110  		_ = b.bg.UpdateClientConnState(name, balancer.ClientConnState{
   111  			ResolverState: resolver.State{
   112  				Addresses:     addressesSplit[name],
   113  				ServiceConfig: s.ResolverState.ServiceConfig,
   114  				Attributes:    s.ResolverState.Attributes,
   115  			},
   116  			BalancerConfig: newT.ChildPolicy.Config,
   117  		})
   118  	}
   119  
   120  	b.children = newConfig.Children
   121  	if update {
   122  		b.stateAggregator.buildAndUpdate()
   123  	}
   124  }
   125  
   126  func (b *bal) UpdateClientConnState(s balancer.ClientConnState) error {
   127  	newConfig, ok := s.BalancerConfig.(*lbConfig)
   128  	if !ok {
   129  		return fmt.Errorf("unexpected balancer config with type: %T", s.BalancerConfig)
   130  	}
   131  	b.logger.Infof("update with config %+v, resolver state %+v", pretty.ToJSON(s.BalancerConfig), s.ResolverState)
   132  
   133  	b.updateChildren(s, newConfig)
   134  	return nil
   135  }
   136  
   137  func (b *bal) ResolverError(err error) {
   138  	b.bg.ResolverError(err)
   139  }
   140  
   141  func (b *bal) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
   142  	b.bg.UpdateSubConnState(sc, state)
   143  }
   144  
   145  func (b *bal) Close() {
   146  	b.stateAggregator.close()
   147  	b.bg.Close()
   148  	b.logger.Infof("Shutdown")
   149  }
   150  
   151  func (b *bal) ExitIdle() {
   152  	b.bg.ExitIdle()
   153  }