超时与重试
如何设置 unary 调用的时间边界?
| 配置 | 文档默认值 | 控制对象 |
|---|---|---|
| ConnectTimeout | 50ms | 建立新连接 |
| RPCTimeout | 0,不限时 | Client 等待一次 RPC |
| ReadWriteTimeout | 5s | Server 网络读写等待 |
| ExitWaitTime | 5s | Server 退出等待 |
- 本地预算: 显式设置 RPCTimeout;Client 的 context 更早到期时会提前返回,超时默认不重试;
- Handler: 读写超时不限制业务执行;业务和数据库仍要主动遵守 context;
- 跨进程: 非 streaming 默认不把 RPC 超时写入 Server context;Thrift 使用 TTHeader、两端 TTHeader MetaHandler 和 Client RPCTimeout,并在 Server 设置
WithEnableContextTimeout(true)(v0.9.0+); - 取消边界: 传递超时预算不等于远端能立即观察调用方手动 cancel;不得把本地返回当作远端写入已撤销;
- 错误识别:
kerrors.IsTimeoutError分类超时;细分业务取消/业务 deadline 需显式启用框架的细粒度错误码;
如何配置失败重试?
- Failure Retry: 超时或指定错误/响应后再次调用;
- Backup Request: 超过延迟阈值并发发送备用请求,先成功者获胜;
- Mixed Retry: 组合 failure 与 backup 策略;
- 建连失败重试: 请求尚未发出时的框架机制;
policy := retry.NewFailurePolicy()
policy.WithMaxRetryTimes(2)
policy.WithMaxDurationMS(800)
cli, err := userservice.NewClient(
"user",
client.WithRPCTimeout(300*time.Millisecond),
client.WithFailureRetry(policy),
)
如何约束重试的副作用?
- 幂等: 开启业务请求重试的首要前提;
- 总预算: 首次调用 + 退避 + 所有重试必须小于上游 deadline;
- 放大: 重试会增加下游流量; 故障时需要停止策略与熔断保护;
- 同节点: 默认优先换实例; 只有明确场景才启用 same-node retry;
- streaming: 不支持常规重试;
- backup: 延迟阈值参考 TP99; 过小会长期制造双倍请求;
如何选择恢复策略?
- 快速失败: 非幂等写、资源已耗尽、明确业务异常;
- Failure Retry: 幂等且瞬时网络/实例错误可恢复;
- Backup Request: 长尾延迟主导且下游容量充足;
- 不确定时: 先设置 timeout 与观测,不开启重试;