跳到正文
docai.cc

DOCAI · 概念 · L3

重试与指数退避怎么做

一句话定义

只对临时性失败做有限次、间隔递增且带随机抖动的重试;确定性错误重试多少次都没用。

专业更新 2026-11-13核验 2026-11-13 · docai 编辑部

它是什么

重试是请求失败后自动再发一次;指数退避是每次重试前等更久;抖动是在等待时间上加一点随机量。三件事合起来,才是一个不会把服务端压垮的重试策略。

它解决的问题是临时性失败:网络抖了一下、服务端短暂过载、限流窗口还没过去。这些情况再试一次大概率能成;但立刻、同时、无上限地重试,只会让情况更糟。

哪些错误该重试

先按状态码分类,再谈退避:

状态 含义 是否重试
429 触发限流 是,按响应头或退避等待
500 / 502 / 503 / 504 服务端临时故障 是
网络超时、连接重置 传输层失败 是,前提是请求幂等
408 请求超时 是
400 请求格式错误 否
401 / 403 鉴权失败、无权限 否,先修凭证和权限
404 地址或资源不存在 否
422 参数语义错误 否

判断标准很简单:错误是不是「这次请求本身」造成的。参数错、key 错、地址错,重试多少次结果都一样。限流本身怎么工作,见什么是限流。

怎么工作

基本形式是:每次失败后等待时间翻倍,再封顶。伪代码如下:

attempt = 0
while attempt < max_attempts:
    result = call()
    if ok(result):
        return result
    if not retryable(result):
        raise result
    if attempt == max_attempts - 1:
        raise result
    delay = min(cap, base_delay * (2 ** attempt))
    sleep(random_between(0, delay))
    attempt += 1

几个参数要一起定:

  • 最大次数:重试次数要有上限,通常几次就够用,再多通常说明问题不在抖动。
  • 总时限:除了次数,还要有总预算。等待时间加到超过业务能容忍的上限,就停止。
  • 单次超时:每次尝试都要有自己的超时,不能因为一次卡死把整个任务拖住。
  • 上限:单次等待封顶,避免退避到几十分钟还没结束。

用「全抖动」——等待时间取零到当前上限之间的随机值——比固定间隔好。多个客户端同时失败时,不会在同一秒一起回来。

Retry-After 与幂等

服务端返回 429 或 503 时,常会带 Retry-After 响应头,告诉你要等多久。它比自己的退避计算更权威,优先遵守;但如果它给出的等待超出业务预算,应该放弃并报警,而不是傻等。

重试前必须确认幂等。查询类请求重发通常安全;创建、扣费、写文件这类操作重发可能产生重复结果。LLM 调用尤其要注意:请求超时不代表服务端没在生成,重发可能重复计费,输出也会出现两份。

能带幂等键就带;不能带,就把「超时后重试」当成一次新的业务请求,记录请求 ID,接受可能重复的代价。成本怎么算,见算清一次请求的成本;报错怎么归类,见读一个 API 报错。

常见误解

  • 「所有失败都值得重试」:确定性错误重试没有意义,还会掩盖真正的问题。
  • 「重试越快恢复越快」:服务过载时,密集重试等于补刀。
  • 「固定间隔重试就行」:所有实例同一节奏重试,会形成一阵一阵的峰值。
  • 「重试只是客户端的事」:服务端也可能重试,两端策略要一起看,否则叠加。

什么时候用

所有会发出网络请求的客户端都应该有这套逻辑,尤其是批处理、长任务和流式输出这类容易遇到超时的场景。最简单的做法是封装一个统一的调用函数,把重试策略放在里面,而不是散落在每个调用点。

什么时候用得上

当你在客户端封装 API 调用、处理 429 与 5xx,或者任务因网络抖动失败需要自动恢复的时候。

常见误解

很多人以为所有报错都值得重试,其实 400、401、403、404、422 这类请求本身的错误,原样重发只会重复失败,还可能放大问题。

来源

定义与事实以以下来源为准;表述与取舍是本站整理的。
  1. [1]OpenAI · Error codes
  2. [2]OpenAI · Production best practices
  3. [3]OpenAI · Rate limits
查看 Markdown

所属专题

相邻概念