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 }