负载均衡原理

主要接口:

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)

  • Close()

    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

  1. type PickerBuildInfo struct {
  2. //就绪链接
  3. ReadySCs map[balancer.SubConn]SubConnInfo
  4. }

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)
}

创建过程:

  1. cc.updateResolverState,调用applyServiceConfigAndBalancer;遍历配置信息,确定一个BalancerName
  2. cc.switchBalancer(newBalancerName),根据balanceName获取builder【balancer.Get(name)】,然后传入builder,调用newCCBalancerWrapper,生成CCBalancerWrapper
  3. 调用bw.updateClientConnState(&balancer.ClientConnState{ResolverState: s, BalancerConfig: balCfg}),将resolver.state传给balancer,由balancer;
  4. balancer调用 cc.NewSubConn()创建subConn;然后调用subConn.Connect
  5. subConn.Conn -> addrConn.connect();然后checkHealth,然后调用:ac.updateConnectivityState(connectivity.Ready, nil);
  6. ac.cc.handleSubConnStateChange(ac.acbw, s, lastErr)
  7. 传给balanceWrapper;cc.balancerWrapper.handleSubConnStateChange(sc, s, err)
  8. scBuffer.Put(); 将事件传给缓冲池;
  9. ccBalancerWrapper.watcher ,收到更新事件,调用V2Balancer.UpdateSubConnState()
  10. V2Balancer.UpdateSubConnState;根据自己的实现,看是否调用:ccBalancerWrapper.UpdateState,将连接置为可用;

负载均衡器使用:

使用过程:

使用_WithDefaultServiceConfig 或 _WithBalancerName ,定义需要使用的负载均衡器;

项目中实现:

还是Jupiter那套;服务器写的,使用的round_robin

round_robin 原理:

  1. 当调用balancerV2.UpdateClientConnState(s balancer.ClientConnState)时,根据resolver.State(内包含address数组)创建多个传输;
  2. 传输创建完后,会进行消息传递,最后传给 balancerV2,调用UpdateSubConnState;
  3. 如果是新的Ready状态的连接,就好调用regeneratePicker,重构picker;
  4. 将balancerV2中的链接遍历,获取出就绪链接,调用 b.v2PickerBuilder.Build(PickerBuildInfo{ReadySCs: readySCs}),将就绪链接传入;
  5. picker.picker时,会根据picker的实现,获取从中的一个就绪链接!

总结:

获取grpc配置中的负载均衡器名,生成合适的负载均衡器,然后将解析器中解析出来的地址创建子链接【addressConn】,子链接创建完成后调用UpdateSubConnState,更新grpc客户端的状态。