ClientConn 结构

ClientConn主要模块包括

  • resolverWrapper ccResolverWrapper【协议解析器】
  • csMgr connectivityStateManager【连接状态管理】
  • blockingpicker pickerWrapper【从中获取连接】
  • balancerWrapper ccBalancerWrapper【负载均衡包装器】

附源码:

  1. type ClientConn struct {
  2. ctx context.Context
  3. cancel context.CancelFunc
  4. // 连接的目标,基于配置来配置!
  5. target string
  6. // 根据Target解析出来的Target
  7. parsedTarget resolver.Target
  8. // 认证,token之类的
  9. authority string
  10. // dialOptions 建立连接选线
  11. dopts dialOptions
  12. // 连接状态管理器
  13. csMgr *connectivityStateManager
  14. // 负载均衡 设置配置
  15. balancerBuildOpts balancer.BuildOptions
  16. // 负载均衡选择器,picker的时候会阻塞!,阻塞的picker
  17. blockingpicker *pickerWrapper
  18. mu sync.RWMutex
  19. // 包装了ClientConn和resolver 解析器
  20. resolverWrapper *ccResolverWrapper
  21. // 服务期配置的参数,弃用
  22. sc *ServiceConfig
  23. // 真实连接,里面包含transport
  24. conns map[*addrConn]struct{}
  25. // Keepalive parameter can be updated if a GoAway is received.
  26. // 保持连接参数
  27. mkp keepalive.ClientParameters
  28. // 当前负载均衡名字
  29. curBalancerName string
  30. // 包装了负载均衡的ClientConn
  31. balancerWrapper *ccBalancerWrapper
  32. // 重试节流器
  33. retryThrottler atomic.Value
  34. // 首次Resolve的时候的事件,
  35. firstResolveEvent *grpcsync.Event
  36. // 唯一标识号
  37. channelzID int64 // channelz unique identification number
  38. // 存储调用成功、失败的个数
  39. czData *channelzData
  40. }

一、启动过程分析

1. 解析出resolver.Target

在conn过程中,首先会解析target【cc.parsedTarget = grpcutil.ParseTarget(cc.target)】,从中解析出resolver.Target,包含三部分:

type Target struct {
Scheme string // 方案
_Authority string
// 认证
Endpoint string // 节点
_}

2. 根据【parsedTarget.Scheme】获取resolverBuilder

resolverBuilder := cc.getResolver(cc.parsedTarget.Scheme)

3. 创建ccResolverWrapper【AddrConn】

// Build the resolver. and update StateChange rWrapper, err := newCCResolverWrapper(cc, resolverBuilder)

  • 创建ccr:= &ccResolverWrapper{}
  • 传入ccr,调用 rb.Build(cc.parsedTarget, ccr, rbo)
  • build中,创建完Resolver后,根据自己的实现解析出[]resolver.Address,传入addrStrs回调ccr.UpdateState,将地址传入到ccr中。
  • ccr 调用 cc.updateResolverState -> cc.maybeApplyDefaultServiceConfig

    4. 选择/创建负载均衡器

  • ###################负载均衡
  • cc.applyServiceConfigAndBalancer(emptyServiceConfig, addrs)
  • 设置负载均衡器,cc.switchBalancer(newBalancerName)
  • builder := balancer.Get(name)
  • cc.balancerWrapper = newCCBalancerWrapper(cc, builder, cc.balancerBuildOpts)

    5. 更新负载均衡器状态【UpdateClientConnState,创建cc.NewSubConn】

  • ccBalancerWrapper.updateClientConnState(&balancer.ClientConnState{ResolverState: s, BalancerConfig: balCfg})

  • 根据balancer版本,调用UpdateClientConnState 或HandleResolvedAddrs
  • V2Balancer.UpdateClientConnState ,
  • 创建subConn
  • b.sc, err = b.cc.NewSubConn(cs.ResolverState.Addresses, balancer.NewSubConnOptions{})
  • 调用 ccBalancerWrapper.NewSubConn【生成acBalancerWrapper】 -> cc.newAddrConn()【生成addrConn】
  • b.sc.Connect() ->acbw.ac.connect(),调用回 addrConn.connect()
  • 开启一个go 异步去连接 go ac.resetTransport()
  • ac.updateConnectivityState(connectivity.Connecting, nil)
  • newTr, addr, reconnect, err := ac.tryAllAddrs(addrs, connectDeadline)
  • ac.startHealthCheck(hctx),updateConnectivityState 协程改 Ready状态
  • ac.cc.handleSubConnStateChange(ac.acbw, s, lastErr) -> cc.balancerWrapper.handleSubConnStateChange(sc, s, err)

    6. 创建连接成功,更新连接状态[UpdateSubConnState]

  • ccb.scBuffer.Put(&scStateUpdate…)

  • ccBalancerWrapper.watcher(), 调用 V2Balancer.UpdateSubConnState(su.sc, balancer.SubConnState{ConnectivityState: su.state, ConnectionError: su.err})
    将连接改为Ready。
  • lb.cc.UpdateState(balancer.State{ConnectivityState: lb.state, Picker: lb.picker})
  • 调回ccBalancerWrapper.UpdateState()
  • 调用ccb.cc.blockingpicker.updatePickerV2(s.Picker),加入picker
  • ccb.cc.csMgr.updateState(s.ConnectivityState) // 更改状态为Ready

二、ClientConn原理梳解:

原理

开门见山来说,ClientConn 就是一个代理连接器,整合了 服务发现 Resolver;负载均衡Balancer;
然后抽象了State,在Dial过程中不断更新Resolver 和BalanceWrapper的State,从而更新csMgr 的State;

结构梳理

ClientConn详解 - 图1

总结:

client启动过程:解析target,获取resolverBuilder,构建resolver传入 resolverWrapper,将解析出来的 ip地址和端口传给resolverWrapper,调用 clientConn的updateResolveState(),clientConn.updateResolveState()会判断有无负载均衡器,则创建负载均衡器,传入解析出来的地址,然后将负载均衡器给BalanceWrapper,然后调用 balanceWrapper的updateClientConnState() 创建subConnect,这里会根据ResolveState的地址来创建多个连接,连接进行tcp握手,http2.0升级后,最后会调用 clientConn 的UpdateSubConnState(),更新clientConn的状态。