重试烧掉的钱:重试策略的成本清单

成本与用量

把一个重试从「多试一次」拆成成本清单:放大倍数怎么算、退避与次数上限怎么设、幂等去重怎么做、日志里怎么认出重试占比。

很多人给请求加了个自动重试,账单就悄悄涨了一截,接口看着还是成功的,根本不知道钱花在哪。问题通常不在重试本身,而在没有上限、没有退避、对不该重试的错误也重试。这篇给一份可以直接照着抄的参数表,再配一套从日志里算重试占比的办法,让你能自己判断是该调参数,还是该换站点或换写法。

很多人给请求加了个自动重试,账单就悄悄涨了一截,接口看着还是成功的,根本不知道钱花在哪。问题通常不在重试本身,而在没有上限、没有退避、对不该重试的错误也重试。

这篇给一份可以直接照着抄的参数表,再配一套从日志里算重试占比的办法,让你能自己判断是该调参数,还是该换站点或换写法。先说结论:重试是放大器,不是保险丝,装之前得先知道它会把什么放大。

先算清一次重试到底贵多少

重试的计费口径是每次请求各算一次。失败的那次如果已经产生输入 token,或者流式吐出过一部分内容,照样计费,不是只算最后成功的那次。很多人以为「重试就是再试一次,成功了才付钱」,实际账单是失败的也算了。

  • 实际放大倍数 = 平均重试次数 + 1,再乘上失败请求的计费比例;一个默认 3 次重试的配置,在失败率高的时段可能把这段用量翻好几倍
  • 最容易失控的是批处理、定时任务和 Agent 循环:单次请求重试被放大成成百上千次,金额是乘出来的不是加出来的
  • 要拿到自己这条链路当时的真实单价与倍率,到 /official-api 或对应站点的报价页核对,不要拿印象里的数字估算

什么该重试,什么重试就是白扔钱

判断标准很简单:这个错误换一次请求,结果会不会不一样。会,就值得重试;不会,重试就是把同一笔费用再交一遍。分不清错误含义时,先看 /api-errors 那张速查表对号入座。

错误类型要不要重试原因
连接超时要暂时性故障,换一次大概率能过
网关类 5xx要对端临时抖动,退避后重试合理
明确的 429要,但带退避限流是暂时的,但要等提示的窗口过去
鉴权失败不要凭据问题,重试结果一样
参数错误不要请求本身有问题,重发同样失败
余额或额度不足不要重试解决不了,只会继续报错
内容被拒不要合规判断,重发还是被拒

拿不准就先记一条铁律:非 2xx 里只有超时、5xx、429 进重试队列,其余直接抛给上层处理。这条规则不适用于你明确知道对端有瞬时抖动但返回了 4xx 的特殊接口,那种情况要单独加白名单。

退避、上限和去重:三个必须写死的参数

  1. 指数退避加随机抖动让并发请求错峰重发,避免同一秒集中重试把限流撞得更狠。退避起点不要设太小,否则等于没退。
  2. 总次数上限和总时长上限都设两个都要设。只设次数不设时长,慢超时会让一次任务拖到几十分钟;只设时长不设次数,短超时场景会疯狂重发。
  3. 所有重试走同一套幂等键同样的业务请求生成同一个 request id,服务端支持幂等头就带上,本地也用这个键做去重,防止同一笔业务被扣两次。
  4. 429 单独处理读到限流响应的重试等待时间按响应提示来,没提示就按退避序列走,别立刻重发。立刻重发只会让限流窗口更长。

可直接照抄的默认参数表

下面这套参数不是最优解,是能先跑起来、不会失控的起点。不同厂商的限流口径和单价不一样,跑一周后再按日志微调。真实单价到 /price-watch 看当时的数字。

场景总次数上限退避起步 / 上限总时长上限
同步接口(用户等结果)2 到 3 次0.5 秒 / 8 秒,带抖动15 到 20 秒
后台批处理3 到 4 次2 秒 / 60 秒5 分钟
流式输出只在建连阶段允许同同步接口30 秒
定时任务与 Agent 循环给整轮设重试预算按单请求退避按任务超时
  • 流式输出一旦开始吐字就别重试,否则用户会看到重复内容且两段都计费
  • 批处理失败进死信队列,不要无限重排
  • 参数不要一次调到底,先按默认跑一周
  • 把重试次数做成配置项,出事时不用改代码

从日志里认出重试占比

不知道重试占多少,调参数就是瞎猜。日志至少记四个字段:请求唯一 id、是否重试、第几次尝试、这次的耗时与用量。缺了任何一个都算不出占比。

  • 重试请求数除以总请求数:看频率,判断重试多不多
  • 重试请求消耗的用量除以总用量:这才是钱的占比,通常比前者更吓人
  • 按状态码分组看:429 占比高就限速或分流,5xx 占比高就换站点或换时段
  • 按业务任务聚合一次:找出少数几个贡献大多数重试的任务,优先修它们
重试本身不贵,贵的是没有边界的重试。
下一步先按参数表把默认值配好,再拿一周日志算出你的重试金额占比;如果 5xx 重试占比一直下不来,多半是站点不稳,到 /sites 看看可信度和延迟记录。

常见问题

我只是加了个重试,为什么账单能翻倍?

因为重试是按请求计费的,不是按最终结果计费。失败那次只要消耗了输入 token 或已经吐出过内容,就照样算钱。加上并发、批处理和 Agent 循环的放大,一个默认 3 次的重试在高失败率时段把某段用量翻几倍很正常。先去日志里算出重试用量占总用量的比例,再决定砍参数还是换线路。

429 到底该不该重试?

该,但必须带退避,不能立刻重发。429 是对方在告诉你「慢点」,立刻重试只会把限流撞得更重,形成越重试越堵的循环。做法是按响应里给的等待时间走,没给就按指数退避加抖动,并且把重试次数计入总预算。如果 429 长期占比很高,说明该换分组、错峰或分散到多家,不是靠重试能解决的。

怎么保证重试不会把同一笔业务扣两次?

给每个业务请求生成一个稳定的幂等键,同一个业务无论试多少次都用同一个键。服务端支持幂等请求头就带上,本地也用这个键在重试队列里做去重,避免同一任务被并发重排。另外流式输出一旦开始吐字就别再重试,那不只是重复计费,还会让用户看到拼接错的重复内容。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。