接口服务出故障的时候,最常见的放大机制就是超时和重试放错了位置。一个下游接口变慢,上游的超时设得比它还长,于是一堆请求卡在那里等着;更糟的是每一层都加了重试,一次请求变成三次、九次,下游本来只是有点慢,被这么一放大直接崩了。

超时和重试的位置,决定了故障是可控的还是雪崩的。超时必须一层比一层短,越往下游留的时间越少;重试只能放在最外层,中间层重试等于自己给自己加倍。这两条规则听着简单,实际配置里违反的非常多。
所以配接口服务之前,先要把请求链路画出来,标清每一层的超时和重试,这张图能直接暴露大部分配置问题。
下面把这件事拆开:先说清超时的分层原则,再讲重试该放哪、怎么放,然后讲重试带来的幂等问题,最后给一套接口服务的配置清单。
上面这些判断落到实际,终究要挑一台机器来跑。下面这张表里的几档,可以对着并发需求看。
| 商家 | 推荐款 | 配置 | 带宽与流量 | 月费 | 档位参照 |
|---|---|---|---|---|---|
| 云途 | — | — | — | — | 见正文 |
| isvoro | — | — | — | — | 见正文 |
| sixtynet | — | — | — | — | 见正文 |
| rabisu | — | — | — | — | 见正文 |
分层超时要有统一的配置入口,散落在各处一定会乱。云途那条产品线从低配起步,先用一台跑通链路再上量,改动成本低。
超时为什么必须分层递减
一次用户请求会经过好几层:浏览器到网关、网关到应用、应用到缓存或数据库、应用再到第三方接口,每一层都有自己的等待时间,如果每层都设成同样的超时值,那最外层等满的时候,内层可能已经等到一半了。判断方法是把每层的超时值列出来,看是不是一层比一层短。
如果外层超时比内层长,那内层先超时的请求会被外层继续等待,这段时间用户看不到任何反馈,只是干等,而外层的连接被占着,无法服务其他请求。判断方法是看有没有出现「下游已经返回错误,上层还在等待」的现象。
如果外层超时比内层短,那外层放弃时内层还在跑,内层的资源没有释放,请求继续占用连接和线程,形成所谓的僵尸请求,累积起来同样会拖垮服务。判断方法是看内层有没有大量还在执行但已无人等待的请求。
正确的做法是留出处理时间,比如用户能接受两秒,那网关设两秒、应用设一点五秒、内部依赖设一秒、第三方接口设八百毫秒,每一层都留一点余量给上一层的收尾。判断方法是按总预算倒推每一层的时间。
还要考虑重试会消耗预算,如果一次请求允许重试一次,那就意味着最坏情况下要跑两遍,总预算要按两遍算,否则第二次一定超时。判断方法是把重试次数乘进预算里。
超时的设置也应该区分读和写,读操作可以设得短一些因为重复执行无害,写操作要留足时间避免执行到一半被中断,而这个中断会留下不一致的中间状态。判断方法是按接口性质分别配置。
验证重试是否放大,要能在下游看到真实请求数。rabisu那个按月付费的档价格不高,单独起一台做下游观察很合适。
重试只能放在最外层
重试的判断依据也要明确,不能对所有失败一律重试,比如返回 404 或者参数校验失败,重试多少次结果都一样,这类应该在配置里排除。判断方法是按错误类型建立白名单。
重试还要区分类别,有些错误重试有意义,比如连接超时、临时不可用,而有些错误重试毫无意义,比如参数错误、权限不足,对这些做重试只是浪费资源。判断方法是看错误码有没有分类。
重试的本质是「这次没成功,再试一次」,而每一次重试都会向下游再发一次请求,如果每一层都做重试,那下游收到的请求量是指数级放大的。判断方法是算一下链路层数和每层重试次数的乘方。
举个例子,三层各重试一次,最坏情况下下游收到八次请求,本来只是偶发超时被放大成八倍压力,而下游正是因为这个压力才超时的,形成正反馈。判断方法是在日志里统计同一个请求 ID 出现的次数。
正确的做法是只在最外层做重试,也就是用户请求的入口那一层,内部各层只做超时控制不做重试,失败就把错误往上抛,由外层决定是否重试。判断方法是检查各层的配置里有没有重试选项。
重试还要有退避策略,连续立即重试会把压力直接堆到下游,而下游此时可能正在恢复,正确的做法是间隔逐渐加长,给下游喘息时间。判断方法是看重试间隔是不是递增的。

重试要有上限和熔断,重试几次之后就放弃,同时如果发现下游整体失败率高,应该暂时停止重试直接返回错误,避免持续加压。判断方法是看有没有失败率阈值和恢复探测。
还有一个常见错误是在网关层做了重试,又在应用层做了一层,两处的重试叠加,实际效果是四倍以上,而配置的时候没人意识到。判断方法是把整条链路的配置集中核对一次。
重试带来的幂等问题
幂等键的生成要注意唯一性,用时间戳或者随机数都可能碰撞,最好用业务主键组合或者专门的唯一标识,而且这个标识要由客户端生成而不是服务端,否则重试时又是一个新的。判断方法是看键的生成位置。
重试意味着同一个操作可能被执行多次,如果这个操作不是幂等的,第二次执行就会产生重复数据或者重复扣款,这个问题在写操作上尤其危险。判断方法是列出有写操作的接口,逐个确认重复执行是否安全。
幂等的定义是执行一次和执行多次结果相同,查询天然幂等,而新增、扣减、发消息都不幂等,这些接口在重试保护下必须有额外机制。判断方法是按接口语义分类。
常见的做法是让客户端生成一个唯一标识随请求带上,服务端在处理前检查这个标识是否处理过,处理过就直接返回上次的结果,没处理过就正常执行并记录。判断方法是看请求里有没有幂等键字段。
还有一种做法是先查后写,但这在并发下不安全,两个请求同时查到「不存在」然后同时插入,结果还是重复,所以必须有唯一约束兜底。判断方法是确认数据库有没有对应的唯一索引。
对于消息类的操作,重复投递会导致重复通知,这时候要做的是让消费端去重而不是指望不重复,因为消息系统一般不保证只投一次。判断方法是看消费端有没有去重逻辑。
所以重试和幂等是一对,引入重试就必须同时引入幂等,否则就是把偶发的超时问题换成了数据问题,而后者更难收拾。判断方法是把两者放在同一份配置里审查。
限流和熔断都按处理能力定阈值,所以机器规格和实际吞吐要能对上。sixtynet那几档规格标得明确,压测出的拐点能直接对应到档位。
接口服务还需要哪些配置
第七个是健康检查,要有一个轻量的探活接口,能反映服务真实状态而不是只返回成功,否则负载均衡会把流量打到一个已经无法工作的实例上。判断方法是看探活接口是否检查了关键依赖。
还有一个是请求体大小限制,接口允许的请求体要设上限,否则一个大请求就能占满内存,而这类问题往往在被人恶意提交时才暴露。判断方法是看有没有大小校验。
第一个是连接数上限,接口服务对下游的连接池要按下游能承受的能力配,而不是按自己的并发数配,这和数据库连接池是同一个道理。判断方法是算总的连接数有没有超过下游的上限。

第二个是限流,入口处要有全局的速率限制,防止突发的流量把服务打垮,限流的阈值按服务的实际处理能力设定,而不是按峰值设定。判断方法是看限流触发后是否还有正常请求能通过。
第三个是熔断,当下游失败率超过阈值时,暂时切断请求直接返回降级结果,等一段时间再试探恢复,这个机制能防止一个下游拖垮整个服务。判断方法是看有没有失败率统计和状态切换。
第四个是排队与拒绝策略,请求超过处理能力时,是排队等待还是直接拒绝,排队会累积延迟、拒绝会损失请求,通常选拒绝更安全,因为排队会导致雪崩式超时。判断方法是看高负载时的响应时间是否失控。
第五个是资源隔离,把不同类别的接口放到不同的资源池里,一个接口出问题不会影响其他接口,隔离的粒度可以是线程池、连接池或者实例。判断方法是看有没有按接口分组的资源。
第六个是日志与追踪,每个请求要有可追踪的标识,能串起整条链路,出问题时才能定位是哪一层慢、哪一层重试了。判断方法是看有没有统一的请求标识贯穿日志。
怎么排查超时和重试的错误配置
还有一个方法是看日志里同一请求的多条记录,如果一条请求在多个层各留下了记录,说明它被多层处理过,配合时间戳能还原整个等待和重试过程。判断方法是按请求标识检索日志。
第一步是画出请求链路,把浏览器、网关、应用、缓存、数据库、第三方都标出来,每一层写上当前的超时和重试配置,这张图能直接暴露问题。判断方法是看有没有哪一层的超时比下一层还长。
第二步是统计每层的错误率和延迟,找出哪一层是真正的瓶颈,如果下游超时率高于上游的错误率,说明上游在等待中把错误掩盖了。判断方法是把两层的指标并排看。
第三步是统计同一请求的重试次数,如果下游收到的请求量远高于上游发出的,就说明中间有冗余的重试。判断方法是用请求标识做去重统计。
第四步是看故障时的放大倍数,正常时的请求量和故障时的请求量对比,放大倍数超过预期就说明重试配置有问题。判断方法是对比故障前后下游的负载。
第五步是做一次故障演练,人为让某个下游变慢,观察上层是否按预期超时和降级,而不是层层等待和重试。判断方法是记录演练时的请求量和响应时间曲线。
最后是把配置做成清单集中管理,所有层的超时和重试放在一处,改动时统一审视,避免某个人在某个角落加了一层重试而其他人不知道。判断方法是看配置是不是散落在各处。
几个常见的误判
误判七是以为超时设长一点更安全,实际上超时越长,故障时的资源占用越久,恢复也越慢,短超时快速失败反而让系统更稳。判断方法是看故障恢复时间的长短。
误判一是以为重试能提高成功率,实际上重试只能处理偶发失败,对持续性故障无效,而且会放大压力,让原本可以恢复的下游彻底崩掉。判断方法是看重试后成功率有没有真的提升。

误判二是把超时设得很长以求稳妥,结果是故障时请求全部堆积,连接被占满,服务完全没有响应,反而不如快速失败让用户重来。判断方法是看故障时的平均响应时间。
误判三是只在应用层配超时不管网关层,网关没有超时限制时会一直等待,用户端看到的是长时间无响应而不是错误页。判断方法是看网关的配置里有没有超时项。
误判四是在同步调用链里做重试却不做幂等,超时重试导致的重复扣款和重复下单,在事后核对时非常难解释。判断方法是看写接口有没有幂等键。
误判五是忽略了下游的重试,自己配了一遍,第三方接口内部也在重试,叠加之后实际次数远超预期。判断方法是问清下游的重试策略。
误判六是配置改完不做验证,超时和重试的效果需要故障场景才能体现,平时看不出来,只能靠演练验证,而多数团队从不演练。判断方法是把演练写进运维计划。
不同业务形态的配置差异
面向用户的页面接口,超时要设得短,因为用户在等,超过两三秒没有响应体验就崩了,宁可快速返回错误让前端给个提示,也不要让用户盯着加载圈。判断方法是看用户能忍受的等待时长,按这个倒推。
面向内部的服务调用,超时可以设得长一些,因为这类调用往往在后台执行,用户看不到,多等一会儿能换来更高的成功率,但要注意别长到占满连接池。判断方法是看连接池大小和平均耗时的关系。
面向第三方的调用最需要谨慎,第三方的稳定性不受你控制,超时要设得短并配合熔断,一旦发现对方大面积超时就直接降级,不要持续尝试。判断方法是看第三方接口的失败率统计。
批处理类的服务恰恰相反,超时要宽松、重试要允许,因为这类任务可以慢慢跑,失败了重来代价也不大,关键是别因为一次网络抖动就整个任务失败。判断方法是看任务的时效要求。
实时性强的业务比如消息推送、在线协作,对超时最敏感,而这类业务往往允许丢弃而不允许延迟,所以策略应该是快速失败加降级,而不是重试等待。判断方法是看业务是延迟敏感还是完整性敏感。
所以配置没有通用值,要按业务对延迟和完整性的偏好来定,先明确这个偏好,再决定超时和重试的组合。判断方法是在方案文档里写清这个取舍。
怎么验证配置是对的
演练要在低峰做,同时准备好快速回滚的开关,因为注入延迟可能会触发真实用户的大量投诉,有一个能立刻取消演练的手段很重要。判断方法是确认开关能在几秒内生效。
第一步是单点注入延迟,人为让某个下游慢下来,看上层是否在预期时间内超时并返回,而不是一直等待。判断方法是记录从注入到返回的时间。
第二步是注入错误,让下游返回错误码,看重试是否只在最外层发生、重试次数是否符合预期、幂等是否生效。判断方法是统计下游收到的请求次数。

第三步是并发压测,在高并发下观察超时和重试的叠加效果,很多问题只在并发时出现,单请求测试完全测不出来。判断方法是看压测时下游的负载倍数。
第四步是看长尾,超时和重试的问题往往体现在长尾请求上,平均值可能是正常的,但有一部分请求耗时特别长,这部分才是用户真正抱怨的。判断方法是看分位数指标。
第五步是看恢复速度,故障恢复后系统能否快速回到正常状态,配置不合理的会有一段恢复期,因为积压的请求还在消化。判断方法是记录故障结束到指标恢复的时间。
验证之后要把结论写下来,包括每层的配置值、验证方式、观察到的现象,这份记录在下次调整时是重要参照。判断方法是看文档能否解释每个数字的来历。
几个容易被忽略的细节
一个是重试的请求要不要重新走一遍完整的限流,如果重试绕过了限流,那原本被限流保护的接口在故障时会被重试打穿。判断方法是看重试路径有没有经过限流层。
另一个是超时后的资源释放,超时只是让调用方不再等待,被调用的服务可能还在执行,如果没有取消机制,这些请求会继续占用资源。判断方法是看有没有传递取消信号。
还有一个是异步任务的超时,这类任务不在请求链路上,但同样需要超时控制,否则一个卡住的任务会一直占用资源,累积之后导致队列满。判断方法是看异步任务有没有执行上限。
监控方面要给超时和重试分别设指标,混在一起看不出是超时多还是重试多,而这两者的处理方向完全不同。判断方法是看监控面板能不能分开看。
告警也要分开设,超时率上升说明下游慢,重试率上升说明有失败在放大,两者同时上升往往意味着已经在雪崩边缘。判断方法是看告警规则是不是按指标分开的。
最后是文档要跟着配置走,配置改了文档不改,下一个人会按错误的理解去调整,而这类问题在交接时最容易出现。判断方法是看配置和文档的更新时间是否接近。
把整篇收一句
超时必须一层比一层短并留出余量,重试只能放在最外层,两者搞反会让一次慢请求变成全站雪崩。
判断方法是画出请求链路,标清每层超时和重试,按用户能接受的时长倒推预算;算一遍层数与重试次数的乘积,看下游放大倍数是否失控。
引入重试就必须引入幂等,写操作要有唯一标识去重或者唯一约束兜底,否则偶发超时会变成数据问题。
最后一句:超时管的是等多久,重试管的是试几次,两者的位置比数值更重要。
本文只为提供市场讯息,所有内容及观点仅供参考,不构成投资建议,不代表本站观点和立场。投资者应自行决策与交易,对投资者交易形成的直接或间接损失,作者及本站将不承担任何责任!
此内容由AI根据文章内容自动生成,并已由人工审核

喜欢
顶
难过
囧
围观
无聊
服务器放在韩国
DODO (DODO) 币
Seppuku (SEPPU
台湾机房和香港