Kratos gRPC连接池与保活需显式配置:设MinConnectTimeout=5s防重试风暴,Keepalive Time=30s、PermitWithoutStream=true保活,禁用WithBlock()改异步拨号;服务端配MaxConcurrentStreams=1000~3000、MaxConnectionAge=10m、Idle=30s。

并发性能瓶颈不在代码逻辑本身,而在连接管理、元数据传递和中间件链路开销上。Kratos 默认配置在 QPS 超过 300 后就容易出现延迟毛刺和连接耗尽,必须针对性调整 transport 层和 selector 行为。
gRPC 客户端连接池与保活参数怎么调?
Kratos 的 grpc.Dial 默认不启用长连接复用,高频短请求会反复触发 TCP 三次握手 + TLS 握手,这是 500ms 延迟的主因之一。
- 必须显式设置
grpc.WithConnectParams:把MinConnectTimeout提高到5*time.Second,避免重试风暴 - 启用保活:
grpc.WithKeepaliveParams中设Time=30*time.Second、PermitWithoutStream=true,否则空闲连接 60 秒后被服务端强制断开 - 禁用默认的
WithBlock(),改用异步拨号 + context 超时控制,防止初始化卡死
服务端最大并发流和连接老化怎么配?
grpc.MaxConcurrentStreams 和 grpc.KeepaliveParams 不配齐,会导致连接堆积、goroutine 泄漏,甚至触发 Linux 的 net.core.somaxconn 限制。
-
MaxConcurrentStreams(1000)是安全起点,若单实例承载 >2k QPS,建议升至 2000~3000 -
MaxConnectionAge设为10*time.Minute,配合MaxConnectionAgeGrace(5 分钟),避免长连接突然中断引发客户端重连雪崩 -
MaxConnectionIdle推荐30*time.Second,比客户端心跳间隔略大,确保双方节奏对齐
元数据透传和中间件链路为什么拖慢并发?
每次 RPC 调用都会经过 metadata.Server()、tracing.Server()、logging.Server() 等中间件,默认实现会做深拷贝或字符串拼接,QPS 高时 CPU 占用飙升。
- 禁用非必要中间件:比如开发环境才用的
recovery.Recovery(),线上应移除 - 元数据提取尽量用
metadata.FromServerContext(ctx)而非ctx.Value(),前者有缓存且类型安全 - 自定义 tracing 中间件时,避免在
handler内部重复生成 traceID,直接复用上下文已有的trace.SpanFromContext(ctx)
P2C 负载均衡器在高并发下怎么避免节点倾斜?
Kratos 默认的 p2c selector 在节点数 >8 或响应时间方差大时,容易因随机采样偏差导致流量打偏,个别实例 CPU 拉满而其他空闲。
- 通过
selector.WithPickerBuilder注册自定义 picker,在prePick阶段过滤掉ewmaLatency > 200ms的节点 - 给每个节点加权重标签(如
weight: "high"),在 WRR 模式下灰度导流,比纯 P2C 更可控 - 禁用
ForcePick机制(默认 3 秒强制选一次),改为基于成功率动态降权,减少无效探测
真正卡住并发上限的,往往不是业务代码里的 for 循环,而是 transport/grpc/resolver 里一次没设对的 MaxConnectionAgeGrace,或是 metadata 中间件里一个没注意的 md.Clone() 调用。这些点不查监控指标(比如 transport/grpc/client/conn_state 和 selector/p2c/latency_ms)根本看不到。











