gRPC 调用返回 DEADLINE_EXCEEDED(code 4),客户端日志为 context deadline exceeded。
客户端在固定超时后收到 DEADLINE_EXCEEDED,流式调用被中断,重试后错误率进一步上升。服务端可能仍在处理,也可能根本没收到请求;监控里客户端错误率和延迟同时升高。
先确认客户端 deadline 与服务端实际处理时间,再判断问题在应用、连接还是网络:
GRPC_GO_LOG_SEVERITY_LEVEL=info GRPC_GO_LOG_VERBOSITY_LEVEL=2 ./client
GRPC_VERBOSITY=DEBUG GRPC_TRACE=http,http2,flowctl,transport ./client
grpcurl -plaintext -max-time 5 -d '{"id":"1"}' <host>:50051 package.Service/Method
服务端指标按状态码和分位数看:
sum(rate(grpc_server_handled_total{grpc_code="DeadlineExceeded"}[5m])) by (grpc_method)
histogram_quantile(0.99, sum by (le, grpc_method) (rate(grpc_server_handling_seconds_bucket[5m])))
Go 的 grpc-prometheus 暴露上述指标;OpenTelemetry 对应 rpc.server.duration 和 rpc.grpc.status_code。再查连接与重传:
ss -tnp state established '( sport = :50051 )' | wc -l
ss -tni '( sport = :50051 )'
nstat -az TcpExtTCPTimeouts TcpExtTCPLostRetransmit TcpRetransSegs
grep -i 'too_many_pings\|GOAWAY' server.log
易误判:DEADLINE_EXCEEDED 是客户端在本地 deadline 到期时生成的,不能证明服务端慢。如果服务端 grpc_server_handling_seconds 显示 20ms 完成,问题可能在连接建立、服务端排队、负载均衡或网络。另一个坑:默认 fail-fast 下连接不可用会立刻返回 UNAVAILABLE;开启 WaitForReady(true) 后会一直等到 deadline,表现为 DEADLINE_EXCEEDED,容易误判成超时。
MaxConnectionAge 强制断开,客户端未及时重建连接。ctx.Err(),区分“自己慢”和“客户端先放弃”。round_robin/xDS,或设置 MaxConnectionAge 打散长连接并定期刷新 DNS。MaxConcurrentStreams 和工作池,避免请求在服务端排队。EnforcementPolicy.MinTime,否则收到 too_many_pings。DEADLINE_EXCEEDED,如何判断是不是服务端处理慢?WaitForReady(true) 后更容易看到 DEADLINE_EXCEEDED?grpc_server_handling_seconds 和 handler 日志;若服务端很快完成,问题在连接、排队或网络。UNAVAILABLE 变成 DEADLINE_EXCEEDED。EnforcementPolicy.MinTime 时,服务端发送 GOAWAY too_many_pings 并断开连接。