连载中 15/20

超时治理:全链路的时间预算

2026-07-14 · 2189 阅读 · 0 评论 · 0 赞

最危险的等待

没设超时的调用是最危险的等待:HTTP 客户端不配超时,默认可能死等几分钟——线程钉死在 socket 上,舱壁的池子被一寸寸抽干,第 1 篇雪崩链的起点就是它。第一条铁律:任何跨网络的调用必须有超时,没有例外。

超时的三层

一个远程调用的时间拆成三段,各管各的:连接超时——建立 TCP 连接的等待,正常几十毫秒,设 500ms~1s 足够,连不上说明下游挂了或网络断了,久等无意义;读超时——连接建立后等响应的时间,按下游 P99 设,这是主战场;整体超时——含重试在内的总预算,防止「单次 800ms × 重试 3 次」把账烧穿。

预算要层层对齐

超时不是单点的数字,是全链路的账本,自顶向下对齐:

用户/网关        预算 3s
 └─ 订单服务     预算 2s
     ├─ 会员 RPC   预算 800ms
     └─ 库存 RPC   预算 500ms
         └─ 库存 DB  预算 300ms

两条对齐规则:上游超时 ≥ 下游耗时 + 余量——订单服务预算 2s,里面两个 RPC 加起来最多 1.3s,留 700ms 给自己的逻辑与 GC;重试要扣预算——库存 RPC 打算重试 2 次,单次 500ms,总预算至少 1.5s,上游的 2s 里装不装得下,要算账。

倒挂是最常见的病:网关给 1s、订单服务给 2s——订单哪怕按时返回,网关也早走了,订单在白算;更糟的是下游超时 3s、上游超时 2s——下游每次都「成功完成」一个没人要的计算,纯属烧 CPU。

超时之后做什么

超时本身不是终点,要和前几篇的机制联动:超时计入熔断统计(慢调用的分子),反复超时自然触发熔断;上游超时后尽量取消下游任务——把调用上下文传下去,客户端断开时下游能感知并中止,别让下游白白算完一份没人等的报表。

HttpClient client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofMillis(500))   // 建连 500ms
        .build();
HttpRequest req = HttpRequest.newBuilder(uri)
        .timeout(Duration.ofMillis(800))          // 读超时 800ms(按 P99 定)
        .build();
// 打算重试 2 次的话,总预算 = 3 × 800ms + 退避间隔,上游要装得下

超时的坑

四个高频坑:默认值陷阱——不配置就是无限等或 20s,上线前全部显式设置;一刀切——大报表和心跳接口同一个超时,按接口分级配置;只设了 HTTP——MyBatis 的 statementTimeout、Redis 客户端、MQ 发送超时,一处都不能漏;预算从不复核——下游改造后 RT 变了,上游超时还停在去年的数,压测时顺手校准。

超时给等待封了顶,重试给失败加了保险,但这两兄弟凑一起就危险——下游正病着,上游齐刷刷重试三次,等于补三刀。下篇聊重试风暴:好心如何办坏事。

503

10 年全栈工程师 · 503咖啡馆主理人

#超时#连接超时#读超时#超时预算#超时倒挂#重试预算

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞