grpc客户端需调用resolver.register注册自定义resolver(如etcd),且必须在grpc.dial前执行;scheme名须与url中严格一致;go 1.21+要求resolver含resolverscheme字段;balancer需withbalancername和withdefaultserviceconfig双配置才生效;状态变更由handlesubconnstatechange处理,pick方法返回ready状态subconn;resolver更新地址后须通过updatestate通知balancer同步。

gRPC客户端怎么注册自定义resolver
Go的gRPC默认只认dns和passthrough两种scheme,想用etcd/zookeeper/consul做服务发现,必须自己注册resolver。不注册就直接panic:「unknown scheme」。
关键点是调用resolver.Register,且必须在grpc.Dial之前执行,否则无效——这个顺序很多人踩坑。
- resolver实现必须满足
resolver.Builder接口,重点是Build方法返回一个resolver.Resolver - 注册时传入的scheme名(比如
"etcd")要和grpc.Dial("etcd://127.0.0.1/svc")里的scheme严格一致,大小写敏感 - Go 1.21+要求resolver必须带
ResolverScheme字段(字符串常量),否则resolver.Get查不到
示例注册:
resolver.Register(&etcdBuilder{...})
为什么Balancer没生效——检查ClientConn配置项
即使写了balancer,90%的情况是它根本没被调用,因为grpc.Dial没开负载均衡开关。
默认情况下,gRPC客户端是「直连第一个地址」,不走balancer逻辑。必须显式启用:WithBalancerName + WithDefaultServiceConfig双保险。
-
WithBalancerName("my_lb"):指定balancer名称,必须和balancer.Register注册时用的名字一致 -
WithDefaultServiceConfig(`{"loadBalancingPolicy": "my_lb"}`):这是v1.27+强制要求,只设WithBalancerName已不够 - 如果用了
round_robin等内置策略,也要配service config,否则降级为pick_first
漏掉WithDefaultServiceConfig会导致balancer的Build方法完全不被调用。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
自定义Balancer里如何处理SubConn状态变化
balancer的核心不是轮询,而是响应后端连接的ConnectivityState变化——上线、断连、空闲、不可达,这些状态驱动你的分发逻辑。
别在HandleSubConnStateChange里直接做请求转发,这里只该更新内部状态和触发重选;真要发请求,得靠Pick方法返回balancer.PickResult。
- 每次SubConn状态变
CONNECTING或READY,应把它加入可用列表;变TRANSIENT_FAILURE或SHUTDOWN就得移除 -
Pick方法被调用时,必须返回一个SubConn,且它的状态要是READY,否则gRPC会报错rpc error: code = Unavailable desc = all SubConns are in TransientFailure - 别缓存
SubConn指针——gRPC可能复用或重建它,要用SubConn.Connect()确保连接活跃
resolver和balancer协作时最容易忽略的细节
resolver负责“发现地址”,balancer负责“怎么用这些地址”,但两者生命周期不自动同步——resolver更新地址列表后,balancer不会自动感知,除非你主动通知。
典型错误是resolver拿到新节点后,直接替换内部地址切片,但balancer还拿着旧的SubConn在用,导致请求发到已下线机器。
- resolver的
ResolveNow方法被调用时,应触发balancer的UpdateState,把新地址列表传过去 - balancer的
UpdateClientConnState里,要对比新旧Addresses,对新增的调用NewSubConn,对删除的调用RemoveSubConn - 所有
SubConn操作(创建/删除/状态更新)必须在balancer自己的goroutine里串行处理,gRPC不保证线程安全
跨网络变更(比如etcd节点增删)和本地balancer状态不同步,是线上最隐蔽的503来源。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










