Kratos 不开箱即用高可用,必须显式配置服务发现、熔断、重试、负载均衡与健康检查;registry 默认为空,需接入 Consul/Etcd/Nacos 并在 server/client 初始化时传入实例,gRPC 客户端须手动添加重试与熔断拦截器,HTTP 与 gRPC 必须共用同一套服务发现与健康检查机制。

Kratos 本身不提供「开箱即用的高可用」,高可用能力必须靠你显式配置和组合关键组件——服务注册与发现、熔断降级、重试、负载均衡、健康检查,缺一不可。只跑通 kratos new 和 go run 远远不够。
服务注册与发现必须启用,不能只靠直连
默认生成的 Kratos 项目里,registry 是空实现(nil),客户端调用会直接 panic 或超时。必须显式接入 Consul/Etcd/Nacos 等注册中心,并在 server/client 初始化时传入实例。
- 服务端注册:在
main.go启动时,用registry.NewConsul(...)创建 registry 实例,再传给app.New(...)的registry参数 - 客户端发现:gRPC client 初始化时,需传入
grpc.WithResolvers(...),且 resolver 必须基于同一注册中心;HTTP client 则依赖http.RoundTripper层的 service discovery middleware - 常见错误现象:
rpc error: code = Unavailable desc = connection closed before server preface received或context deadline exceeded,大概率是 client 没配 resolver 或 server 没注册成功 - 注意:Kratos 的
registry接口是抽象层,但具体实现(如consul.New)需单独go get,官方不打包进核心库
gRPC 客户端必须手动加重试和熔断,没有默认策略
Kratos 的 grpc.Client 默认不带重试、不带熔断,所有容错逻辑都得你自己组装。直接用 grpc.Dial(...) 创建的 conn,一次失败就彻底失败。
- 重试:用
grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(...)),注意设置grpc_retry.WithMax(3)和grpc_retry.WithBackoff(...) - 熔断:集成
gobreaker或resilience-go,写一个自定义 UnaryClientInterceptor,在调用前检查熔断器状态,失败后更新状态 - 别漏掉超时控制:每个 RPC 调用必须带
ctx, cancel := context.WithTimeout(ctx, 5*time.Second),否则上游超时无法传导 - 性能影响:重试 + 熔断会增加少量延迟和内存占用,但相比雪崩风险,这是必要代价;建议在非幂等操作(如 POST /order)上禁用重试
HTTP 和 gRPC 必须共用同一套服务发现与健康检查机制
如果你同时暴露 HTTP 和 gRPC 接口(比如用 grpc-gateway),两个协议的后端服务发现不能割裂。否则会出现 HTTP 请求能通、gRPC 请求 503 的情况。
- 健康检查路径要统一:server 启动时注册的 health check endpoint(如
/health)必须被注册中心定期探测,且返回 200 才算 healthy - gRPC 的
health.CheckResponse和 HTTP 的GET /health应该共享同一份内部状态(例如共用一个atomic.Bool标记是否 ready) - 避免陷阱:不要让 grpc-gateway 自己去轮询后端 gRPC 地址(如
localhost:9000),而应通过服务名(如greeter.service.consul)解析,走同一套 DNS/Resolver 逻辑 - 兼容性注意:某些注册中心(如早期 Etcd v2)不支持 TTL 续租,会导致服务频繁上下线,建议用 Etcd v3+ 或 Consul
Wire 依赖注入必须覆盖所有中间件和客户端生命周期
Wire 不只是用来 new service,它必须管理 registry、client、breaker、logger 等所有有状态组件的创建顺序和复用。手写 newXXXClient() 很容易导致连接泄漏或配置不一致。
- 把 client 构建逻辑放进 wire:例如
ProvideGreeterClient函数中,用grpc.Dial(...)+ interceptor + resolver 一次性构造好可复用的*grpc.ClientConn - 确保单例:所有对同一服务的 client(比如多个 handler 都要调
user服务),必须从 wire graph 中获取同一个实例,而不是每次 new - 容易踩的坑:wire gen 后没运行
go generate ./...,或wire.Build里漏了某个 provider,导致 runtime panic 报provider not found for *xxx.Client - 调试技巧:在 wire 生成的
wire_gen.go里加日志,确认 client 是否真被初始化;用net.Conn的Close方法验证是否被正确释放
最常被忽略的一点:高可用不是配置开关,而是拓扑感知。Kratos 不会自动感知网络分区、机房故障或跨 AZ 延迟突增。你需要结合注册中心的 region/tag 机制做分组路由,并在 client 层写 fallback 逻辑(比如降级到本地缓存或备用集群),这部分只能靠业务代码兜底。


















