云上接口的超时分层:把失败留在该失败的那一层
做云上业务时,最容易被低估的不是“会不会超时”,而是“超时发生在哪一层、由谁来收尾”。把网关、应用和下游客户端的超时都设成同一个数,看起来整齐,线上却经常出现两种怪象:要么上游先断开、下游还在空转;要么下游已经失败,上游仍在傻等,把线程池和连接池一起拖垮。我把一次调用看成四段预算,而不是一个数字。第一段是用户能感知的总预算。页面或开放接口如果承诺三秒内给出结果,这三秒就是硬上限,后面所有层级都只能从里面扣,不能各自再发明一个更大的数。
第二段是网关预算。网关要比总预算略短,留出把错误页、降级结果或请求标识写回去的时间。网关超时后应立刻断开上游连接,并给请求打上可追踪的标识,避免客户端重试时无法和原请求对上。
第三段是应用自己的处理预算。鉴权、参数校验、本地缓存命中,这些不该占用下游的时间。应用在真正发起远程调用之前,先看剩余预算还够不够一次完整往返;不够就直接走降级,而不是抱着侥幸再打出去。
第四段是下游客户端预算。它必须短于应用剩余预算,并且和重试次数一起计算。重试不是免费的:两次重试意味着三次尝试,预算要按次数分摊。没有幂等保证的写操作,默认不重试;只对查询、或带幂等键的创建做有限重试。
配套有三条容易漏掉的约束。一是连接超时和读取超时分开设。连接超时反映的是网络和建连,通常应很短;读取超时才对应业务处理。混在一个参数里,故障时你分不清是线路问题还是下游变慢。二是超时要带着取消。上游超时之后,如果下游线程还在跑,失败并没有真正结束,只是换了个地方堆积。能传递取消信号就传递,不能传递至少要限制在途请求数。三是把超时当成一种正常结果来记录:哪一层触发、剩余预算、下游名称、是否发生重试。没有这些字段,告警只能告诉你“变慢了”,不能告诉你该改哪一个数。
最后用一个小例子收束。假设总预算 3000 毫秒,网关留 2800,应用自身逻辑预留 200,下游读取预算就是 2600。若允许一次重试,单次读取应压到 1200 左右,并在两次尝试之间留出抖动间隔,避免惊群。数字可以按业务改,分层的顺序不该改:先定用户预算,再逐层扣减,重试必须吃同一份预算,而不是在预算之外再加时间。
这样做的收益很具体。故障时失败会停在正确的层,连接池不会被慢调用占满,重试也不会把下游的抖动放大成雪崩。超时不再是拍脑袋的配置项,而是一张可以复盘的预算表。
- 点赞
- 收藏
- 关注作者
评论(0)