Balancer
gRPC balancer
背景
接着上篇《gRPC 插件式编程之Resolver》,gRPC 将 target
解析为 resolver.Target
后,通过 resolver.Builder.Build
方法调用
resolver.ClientConn.UpdateState(State) error
方法,该方法做了哪些事情呢,我们本篇接着看源码往下走。
UpdateState
UpdateState 的调用会调用 grpc.ClientConn.updateResolverState
方法,该方法主要做了如下工作:
- ServiceConfig 处理
- BalancerWrapper 创建
- 调用
balancer.updateClientConnState
方法 执行负载均衡逻辑更新
func (cc *ClientConn) updateResolverState(s resolver.State, err error) error {
...
cc.maybeApplyDefaultServiceConfig(s.Addresses)
...
cc.applyServiceConfigAndBalancer(sc, configSelector, s.Addresses)
...
// reference: balancer_conn_wrappers.go:164
// bw.updateClientConnState -> ccBalancerWrapper.updateClientConnState
bw.updateClientConnState(&balancer.ClientConnState{
ResolverState: s, BalancerConfig: balCfg})
...
}
温馨提示
这里先以搞懂 gRPC 主流程思路为主,不扣太细节的东西,比如一些
GRPCLB
处理、error处理,ServiceConfigSelector 处理等可以查看源码。
bw.updateClientConnState
调用本质是 ccBalancerWrapper.updateClientConnState
而 ccBalancerWrapper.updateClientConnState
就做了一件事情,调用 balancer.Balancer.UpdateClientConnState
方法
func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error {
ccb.balancerMu.Lock()
defer ccb.balancerMu.Unlock()
return ccb.balancer.UpdateClientConnState(*ccs)
}
到这里,我们想看 balancer
源码逻辑有两种途径
- 自己实现的
balancer.Balancer
- gRPC 提供的
balancer
为了阅读源码,我们先去阅读 gRPC 提供的几个 balancer
中的一个进行流程理解,后续再介绍如何自定义一个 balancer
gRPC Balancer
gRPC 提供了几个负载均衡处理,如下:
- grpclb
- rls
- roundrobin
- weightroundrobin
- weighttarget
为了好理解,我们挑一个简单的负载均衡器 roundrobin
继续阅读。
负载均衡从哪里获取?通过前面 cc.maybeApplyDefaultServiceConfig(s.Addresses)
方法中的源码可知,balancer.Balancer
由 balancer.Builder
提供,我们看一下 balancer.Builder
接口
// Builder creates a balancer.
type Builder interface {
// Build creates a new balancer with the ClientConn.
Build(cc ClientConn, opts BuildOptions) Balancer
// Name returns the name of balancers built by this builder.
// It will be used to pick balancers (for example in service config).
Name() string
}
roundrobin
roundrobin 是 gRPC 内置的负载均衡器,其和 resolver
一样都是通过插件式编程提供扩展,在源码中,我们可知,
roundrobin 在 init
函数中对 balancer.Builder
进行了注册,其中 baseBuilder
是 balancer.Builder
的实现,
上文我们得知, balancer.Balancer
由 balancer.Builder.Build
提供,通过 baseBuilder.Build
方法我们知道 gRPC 的
balancer
底层是由 baseBalancer
实现,部分源码如下:
roundrobin.go
// newBuilder creates a new roundrobin balancer builder.
func newBuilder() balancer.Builder {
return base.NewBalancerBuilder(Name, &rrPickerBuilder{
}, base.Config{
HealthCheck: true})
}
func init() {
balancer.Register(newBuilder())
}
balancer.go
func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
bal := &baseBalancer{
cc: cc,
pickerBuilder: bb.pickerBuilder,
subConns: resolver.NewAddressMap(),
scStates: make(map[balancer.SubConn]connectivity.State),
csEvltr: &balancer.ConnectivityStateEvaluator{
},
config: bb.config,
}
bal.picker = NewErrPicker(balancer.ErrNoSubConnAvailable)
return bal
}
沿着 UpdateState
环节最后一个方法 ccb.balancer.UpdateClientConnState(*ccs)
调用阅读,其实最终来到了
baseBalancer.UpdateClientConnState
方法,我们查看一下源码:
func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
...
addrsSet := resolver.NewAddressMap()
for _, a := range s.ResolverState.Addresses {
addrsSet.Set(a, nil)
if _, ok := b.subConns.Get(a); !ok {
sc