上篇笔记中梳理了一把 resolver 和 balancer,这里顺着前面的流程走一遍入口的 ClientConn 对象。
ClientConn
// ClientConn represents a virtual connection to a conceptual endpoint, to
// perform RPCs.
//
// A ClientConn is free to have zero or more actual connections to the endpoint
// based on configuration, load, etc. It is also free to determine which actual
// endpoints to use and may change it every RPC, permitting client-side load
// balancing.
//
// A ClientConn encapsulates a range of functionality including name
// resolution, TCP connection establishment (with retries and backoff) and TLS
// handshakes. It also handles errors on established connections by
// re-resolving the name and reconnecting.
type ClientConn struct {
ctx context.Context
cancel context.CancelFunc
target string
parsedTarget resolver.Target
authority string
dopts dialOptions
csMgr *connectivityStateManager
balancerBuildOpts balancer.BuildOptions
blockingpicker *pickerWrapper
mu sync.RWMutex
resolverWrapper *ccResolverWrapper
sc *ServiceConfig
conns map[*addrConn]struct{}
// Keepalive parameter can be updated if a GoAway is received.
mkp keepalive.ClientParameters
curBalancerName string
balancerWrapper *ccBalancerWrapper
retryThrottler atomic.Value
firstResolveEvent *grpcsync.Event
channelzID int64 // channelz unique identification number
czData *channelzData
}
首先是 ctx 和 cancel 两个字段,之前好像有看到什么最佳实战说不要把 context 字段放在 struct 里传递而要放在 func 里传递,但是这里确实属于一个非常合理的场景:管理连接的生命周期,这个 ctx 和 cancel 都是来自建立连接时的 DialContext,标准库的 net.Conn 的结构体中也有同样的两个字段,这样请求上下文中建立的连接,可以在请求结束时安全释放掉。ClientConn 中派生出的 goroutine,也能通过 cancel 函数安全地关闭掉。
target、parsedTarget、authority、dopts 似乎都属于比较原始的参数。
csMgr 用于管理 ClientConn 总体的连接状态,先放一下,后面详细看。
resolverWrapper、conns、curBalancerName、balancerWrapper、firstResolveEvent 跟名字解析、负载均衡相关,上一篇笔记中简单看过一点。retryThrottler 大约是重试的退避策略,还没有了解过。
sc *ServiceConfig 是服务端给出的服务参数信息,大约是 maxRequestMessageBytes、timeout 之类的控制信息,可以具体到接口级别。mkp keepalive.ClientParameters 也是参数信息,与 keepalive 相关。
channelzID 和 czData 与 channelz 的信息相关,channelz 是 grpc 内部的一些埋点监控性质的信息,大体上是一个异步的 AddTraceEvent 然后汇聚数值,看代码的时候应该可以忽略这部分。
ClientConn 与 resolverWrapper / balancerWrapper 的交互
clientConn 与 resolver / balancer 之间的交互在上一篇笔记中简单梳理过,好处是接口比较明确,所以交互比较清晰。clientConn 与 resolverWrapper / balancerWrapper 之间的交互都是具体的方法,手工梳理一下。
resolverWrapper 对 clientConn 的调用有 updateResolverState。
clientConn 对 resolverWrapper 的调用有 resolveNow。
clientConn 对 balancerWrapper 的调用有:
- resolveError:调用来自 clientConn 的 updateResolverState 方法,该方法是被 resolverWrapper 所调用的。
- handleSubConnStateChange,调用来自 cli