负载均衡原理
主要接口:
1. balancer.ClientConn
- NewSubConn([]resolver.Address, NewSubConnOptions) (SubConn, error)
调用cc.newAddrConn(addrs, opts),从address 中创建一个连接;返回grpc.addrConn,此时的addrConn并未开始传输
- RemoveSubConn(SubConn)
移除子链接
- UpdateBalancerState(s connectivity.State, p Picker)
弃用,使用UpdateState来替代
- UpdateState(State)
更新csMgr和blockingpicker的状态;最后成功才调用
传入picker和状态
- ResolveNow(resolver.ResolveNowOptions)
调用resolver的resolveNow
- Target() string
返回dial 的target
2. balancer.Builder
Build(cc ClientConn, opts BuildOptions) Balancer
返回builder
Name() string // 返回builder名字,balancer.Get()根据名字获取builder
3. Balancer【弃用】
HandleSubConnStateChange(sc SubConn, state connectivity.State)
弃用,回去调用V2Balancer .UpdateSubConnState
HandleResolvedAddrs([]resolver.Address, error)
-
4. V2Balancer
UpdateClientConnState(ClientConnState) error
传入balancer.ClientConnState,包含config和resolver.State
ResolverError(error)
UpdateSubConnState(SubConn, SubConnState)
更新某个子链接状态 ;会调用 cc.UpdateState
Close()
5. SubConn
UpdateAddresses 更新此 SubConn 中使用的地址。 gRPC 检查当前连接的地址是否仍在新列表中。如果它在列表中,将保持连接。如果它不在列表中,连接将正常关闭,并创建一个新连接
UpdateAddresses([]resolver.Address)
调用adressConn.connect()
Connect()
6. V2PickerBuilder()
传入就绪的链接给picker管理
Build(info PickerBuildInfo) balancer.V2Picker
type PickerBuildInfo struct {//就绪链接ReadySCs map[balancer.SubConn]SubConnInfo}
7. balancer.V2Picker
根据info,返回一个就绪的链接
Pick(info PickInfo) (PickResult, error)
type PickInfo struct {
// 调用方法名
// with. The canonical format is /service/Method.
FullMethodName string
// 上下文
Ctx context.Context
}
// PickResult contains information related to a connection chosen for an RPC.
type PickResult struct {
// 就绪的subConn:acBalancerWrapper,里面封装addrConn
SubConn SubConn
// 完成调用后回调
Done func(DoneInfo)
}
创建过程:
- cc.updateResolverState,调用applyServiceConfigAndBalancer;遍历配置信息,确定一个BalancerName
- cc.switchBalancer(newBalancerName),根据balanceName获取builder【balancer.Get(name)】,然后传入builder,调用newCCBalancerWrapper,生成CCBalancerWrapper
- 调用bw.updateClientConnState(&balancer.ClientConnState{ResolverState: s, BalancerConfig: balCfg}),将resolver.state传给balancer,由balancer;
- balancer调用 cc.NewSubConn()创建subConn;然后调用subConn.Connect
- subConn.Conn -> addrConn.connect();然后checkHealth,然后调用:ac.updateConnectivityState(connectivity.Ready, nil);
- ac.cc.handleSubConnStateChange(ac.acbw, s, lastErr)
- 传给balanceWrapper;cc.balancerWrapper.handleSubConnStateChange(sc, s, err)
- scBuffer.Put(); 将事件传给缓冲池;
- ccBalancerWrapper.watcher ,收到更新事件,调用V2Balancer.UpdateSubConnState()
- V2Balancer.UpdateSubConnState;根据自己的实现,看是否调用:ccBalancerWrapper.UpdateState,将连接置为可用;
负载均衡器使用:
使用过程:
使用_WithDefaultServiceConfig 或 _WithBalancerName ,定义需要使用的负载均衡器;
项目中实现:
还是Jupiter那套;服务器写的,使用的round_robin
round_robin 原理:
- 当调用balancerV2.UpdateClientConnState(s balancer.ClientConnState)时,根据resolver.State(内包含address数组)创建多个传输;
- 传输创建完后,会进行消息传递,最后传给 balancerV2,调用UpdateSubConnState;
- 如果是新的Ready状态的连接,就好调用regeneratePicker,重构picker;
- 将balancerV2中的链接遍历,获取出就绪链接,调用 b.v2PickerBuilder.Build(PickerBuildInfo{ReadySCs: readySCs}),将就绪链接传入;
- picker.picker时,会根据picker的实现,获取从中的一个就绪链接!
总结:
获取grpc配置中的负载均衡器名,生成合适的负载均衡器,然后将解析器中解析出来的地址创建子链接【addressConn】,子链接创建完成后调用UpdateSubConnState,更新grpc客户端的状态。
