生产环境必须用 discovery:///service-name 格式,硬写 ip:port 会失去服务发现能力;endpoint 必须带 discovery:/// 前缀,少一个斜杠会 panic;服务名需与注册时 appid 完全一致;grpc.withdiscovery 必须传入 registry.discovery 实例,不可为 nil;负载均衡器名称仅支持 "round_robin"、"wrr"、"random";watch 失效多因注册中心客户端超时或连接配置不当。

生产环境必须用 discovery:///service-name 这种格式,硬写 IP:PORT 会失去服务发现能力,上线即故障。
endpoint 字符串必须带 discovery:// 协议前缀
gRPC Dial 时传入的地址不是传统 URL,而是 Kratos 自定义的解析协议。不加前缀会被当成直连模式,完全绕过注册中心。
-
"127.0.0.1:9000"→ 直连,无视grpc.WithDiscovery -
"discovery:///user-service"→ 正确,触发 resolver 解析流程 - 注意三个斜杠:
discovery:///不是discovery://,少一个会 panic - 服务名(如
user-service)必须与注册时的appid完全一致,大小写敏感
grpc.WithDiscovery 必须传入 registry.Discovery 实例
这个参数不是可选的“开关”,而是服务发现链路的起点。传 nil 或类型错误会导致 Dial 失败,错误信息通常是 "failed to resolve address" 或空指针 panic。
- Consul 场景:用
consul.New(client)构造的实例,不是 raw api.Client - Nacos 场景:必须是
nacos.New(namingClient),不是clients.NewNamingClient - 不能复用
registry.Registrar实例 —— Registrar 是注册用的,Discovery 是发现用的,二者接口不同 - Wire 注入时要分开声明:一个 ProviderSet 给 Registrar,另一个给 Discovery
balancerName 必须与内置策略名严格匹配
Kratos 内置的负载均衡器名称是固定字符串,拼错或用自定义名但没注册,会导致连接建立后请求直接失败,现象是 gRPC status code 14(UNAVAILABLE)且无日志。
- 可用值只有:
"round_robin"、"wrr"(加权轮询)、"random" -
"least_request"或"p2c"等常见策略 Kratos 默认不支持,需自行实现并调用balancer.Register - 若用
wrr,必须确保每个实例注册时带了weight元数据,否则默认为 1,失去加权意义 - 不设该选项时默认为
"round_robin",但显式写出更利于排查
watch 机制失效常因 consul/nacos 客户端配置超时
服务列表变更无法实时感知,多数情况不是代码逻辑问题,而是底层注册中心客户端的连接/超时参数不合理。
- Consul client 的
api.Config.Timeout建议设为 ≥ 5s,低于 2s 容易因网络抖动断开 watch 连接 - Nacos client 的
TimeoutMs和BeatInterval需匹配 —— 若心跳间隔是 5s,超时至少设为 8s - 所有注册中心客户端必须启用长连接(如 Consul 的
http.Transport.MaxIdleConnsPerHost = 100),否则频繁重建连接会丢事件 - 日志里出现
"watch cancelled"或反复"poll returns -304"后静默,基本可锁定为客户端连接不稳定
真正难调试的点往往不在 Kratos 层,而在注册中心客户端与网络中间件(如 Istio Sidecar)的交互细节 —— 比如 Envoy 对 HTTP/2 HEADERS 帧的拦截可能让 Consul watch 流式响应中断,这种问题需要抓包确认,而不是改 Kratos 配置。











