W5D3 学习手册 1.工具超时2.整体超时3.可重试性4.退避 5.防雪崩6.补偿7.预算联动8.无限重试 9.Temporal10.可观测达标①达标② 自测速记

FDE W5 Day 3 学习手册 · 超时、重试与退避、补偿

W5 Day3 · A 级(必须掌握,面试核心)· 4h · 学完能讲透"哪些错该重试、怎么退避、重试失败怎么补偿、为什么不能无限重试"

本日定位:W5D2 讲了预算是"熔断丝"。Day3 讲熔断之后怎么办——工具超时、失败重试、指数退避+抖动、重试耗尽后的补偿动作。这是 Agent 面对"下游不稳定"时的韧性三件套。
学完能回答:① 超时怎么设(单工具 vs 整体);② 哪些错误可重试、哪些不可;③ 退避为什么能避免雪崩;④ 补偿动作(回滚/转人工)怎么设计;⑤ 为什么不能无限重试、执行预算怎么和重试联动。
使用方法:通读原理 → 重点看「工程含义」「面试话术」「易错点」→ 做自测清单 → 配合《FDE-W5D3-评测题.md》。选中不熟的词可标注(左下★重要 / 右下📌待查)。候选人背景:36岁,Java+大数据+医疗保险行业,示例围绕特药理赔/保险知识库。

一、超时设计①:工具调用超时

每个工具调用都要有超时时间,防止下游无响应时调用方无限等待、资源被挂死。

future = invokeAsync(tool); result = future.get(TIMEOUT, TimeUnit) // 超时抛 TimeoutException → 受控错误
对 Java 背景:用 CompletableFuture / Future.get(timeout) 或 Resilience4j 的 TimeLimiter。超时是"下游不可靠"时的第一道保护,但必须配合"取消"和"后续决策"才有意义。
工具调用超时 = 给每个工具设最大等待时间,超时抛受控错误。不同工具超时不同(缓存短、外部接口长)。超时后还要取消底层请求并决定重试/换路/转人工。
① 超时设太长失去保护意义、设太短会误杀慢但正常的调用——要按 P99 延迟压测定,留余量(如 P99×1.5)。② "超时返回但后台没取消"会造成连接/线程泄漏,必须真正 cancel。③ 超时和 W5D2 的"整体时间预算"是两个层次:单工具超时管一个点,整体预算管整个 Loop。

二、超时设计②:整体 Agent 超时

除了单工具,整个 Agent 调用也要有总时长上限(deckline),防止循环 + 多工具把整体拖死(见 W5D2 时间预算,这里从"超时触发"角度再看)。

超时层次保护对象超限动作
单工具超时单个下游调用返回超时受控错误 → 重试/换路
整体 Agent 超时整个 Loop/连接/线程中断循环 → 优雅结束(PARTIAL)
整体 Agent 超时(时间预算)比单工具超时更上层:单工具超时兜底慢工具,整体超时兜底整个循环卡死。两者配合,缺一不可。
① 整体超时要用绝对 deadline(now+budget)每轮检查,不靠"每轮计时累加"——累加因调度抖动不准。② 超时中断要"安全":已做状态能恢复(Checkpointer),不能中断即全丢(呼应 W5D1)。

三、重试:哪些错误可重试,哪些不可

错误类型可重试?原因例子
网络超时/连接失败✅ 可瞬时、下游可能已恢复医保接口 504、连接池耗尽
限流 429 / 503✅ 可稍后重试可过下游限流,退避后重试
5xx 服务端错误⚠️ 视情况可能瞬时也可能持续500 偶发可重试,持续则转人工
业务校验失败(4xx 参数错/无权限)❌ 不可重试同样会失败,需改输入保单号不存在、参数不合法
领域规则冲突❌ 不可数据状态问题,重试无效理赔已结案不能再提交
重试的前提是"错误是瞬时的、且重试后可能成功"。业务校验失败是"输入不对",重试一万次还是错,只会浪费预算——这类要立刻反馈给模型/用户改输入,或转人工。
可重试=瞬时错误(网络超时/429 限流/偶发 5xx);不可重试=业务校验失败(参数错/无权限/状态冲突),重试无效、要改输入或转人工。判断核心是"这次失败是暂时的吗"。
① "5xx"不能一刀切重试——持续 500 重试只会增加下游压力(雪崩),要配合"重试次数上限 + 持续失败则转人工"。② 业务校验失败若被当成"可重试"反复重试,会白白耗光次数预算还不出结果。③ 重试要带幂等键,否则重复提交(如再次提交理赔)造成重复副作用。

四、退避:指数退避 + 抖动

重试不能"立刻连发",否则瞬时故障还没恢复又被打爆。用指数退避:每次重试间隔成倍增长,并加抖动(jitter)避免"重试风暴同步"。

sleep = base × 2^(attempt-1) + random(0, jitter)  // 如 0.1s, 0.2s, 0.4s, 0.8s + 随机抖动
for attempt in 1..MAX:
    try: return invoke(tool)
    except Retryable as e:
        if attempt == MAX: break
        delay = min(cap, base * 2**(attempt-1)) + random(0, jitter)
        sleep(delay)
return compensate()   # 重试耗尽 → 补偿
指数退避是分布式系统的标准实践(HTTP 429 规范也建议)。Java 里 Resilience4j 的 @Retry + waitDuration/enableExponentialBackoff 直接支持;也可自己实现。关键是"退避 + 上限 + 抖动"三件套。
重试退避 = 间隔指数增长(0.1→0.2→0.4…)且设上限,再加随机抖动避免同步重试。既不立刻连发打爆下游,又不无限等。
① 不加抖动,所有失败请求会在同一时刻"集体重试",瞬间把刚恢复的下游又打挂——这就是重试风暴。② 退避上限必须设,否则第 10 次等几分钟,整体超时先到了。③ 退避间隔计入 W5D2 的时间预算——退避太久整体超时也会触发。

五、退避为什么能避免雪崩

雪崩:下游故障 → 上游大量重试 → 下游压力更大 → 彻底崩溃 → 上游全挂。退避 + 抖动打破这个正反馈。

无退避:故障 → 全部立即重试 → 下游 QPS 翻倍 → 更慢 → 更多超时 → 崩 有退避+抖动:故障 → 请求分散在不同时间点重试 → 下游压力可控 → 逐步恢复
雪崩是企业级最怕的连锁故障。退避+抖动是"削峰",限流是"控流",熔断是"断流"。三者配合才能在下游抖动时保护整体可用性。保险核心系统在高峰期尤其怕这个。
雪崩 = 故障引发大量同步重试把下游彻底打垮。退避+抖动把重试波摊平、削峰,配合限流(控流)和熔断(断流),三重保护避免连锁崩溃。
① 退避 alone 不够——如果下游持续 500,无限退避只是"慢死",必须配合"重试次数上限 + 熔断 + 转人工"。② 抖动一定要"全抖动"(在 0~cap 间随机)而非"固定+小抖动",否则仍有周期性同步峰。③ 雪崩不止在重试:Agent 并发调用多个下游时,一个慢下游也会拖垮线程池,要靠隔离(W5D2)+ 限流。

六、补偿:重试失败后的补偿动作

重试耗尽仍失败,不能"抛异常让用户懵",要做补偿(Compensation):把系统从"部分完成"拉回一致状态。

补偿动作做法适用
回滚已做部分撤销本事务内已执行的副作用多步写操作,前几步成功了
标记人工介入留工单/告警,转人工处理高风险(理赔提交失败)
降级返回部分结果返回 PARTIAL + 缺失说明查询类,能答多少答多少
幂等去重用 request_id 防重复提交重试已部分成功的写操作
补偿是" saga 模式"的思想:长流程没有分布式事务,每一步配一个补偿操作。Agent 调了"暂存草稿"成功、但"提交审批"失败,就要回滚草稿或标记人工。对保险这类强一致+强审计场景,补偿必须可留痕、可复盘。
重试耗尽 → 补偿:回滚已做部分 / 标记人工介入 / 降级返回部分结果 / 幂等去重。核心是"不让系统卡在不一致状态"。高风险(理赔提交失败)直接转人工并留痕。
① 补偿本身要幂等——"回滚草稿"若被执行两次不能出错。② 降级返回 PARTIAL 时绝不能"假装成功"(呼应 W5D2),必须显式标状态。③ 标记人工介入要带"上下文摘要",让人接手时一看就懂查到哪、卡在哪,否则人工成本更高。

七、重试 / 退避 / 补偿与执行预算的联动

重试不是免费的——它消耗次数预算、Token 预算、时间预算。三者必须联动,否则重试会悄悄突破预算。

重试消耗:次数 +1、token +N、时间 +退避间隔 预算检查:每次重试前先查 (次数
重试是"用预算换成功率"——要有上限。工程上把"重试预算"作为执行预算的一部分统一管控,重试前先校验预算,任一超限即进入补偿/优雅结束,而不是无脑重试。
重试消耗次数+Token+时间三种预算,必须联动:每次重试前先校验预算,超限即进入补偿/优雅结束。重试本质是"用预算换成功率",要有上限。
① 常见 bug:重试逻辑没计次数预算,导致"重试把次数耗光"但主流程还以为没超。② 退避 sleep 别忘了算进整体时间预算,否则退避 30s×5 次直接超整体 deadline。③ 预算联动要在 Runtime 层统一做,重试代码里各自判断容易漏。

八、重试的边界:为什么不能无限重试

重试必有上限:MAX_RETRY(如 3–5 次)+ 退避上限 + 总预算上限 → 超限即补偿
无限重试是反模式。正确做法:有限次重试(指数退避+抖动)+ 预算约束 + 重试耗尽转补偿/人工。把"尽量成功"和"及时认输"平衡好。
不能无限重试:成本爆炸、延迟超时、雪崩下游、且对业务错误无效。正确做法=有限次(3–5)+退避+预算约束+耗尽转补偿/人工。
① 有人觉得"多试几次总能成",但持续失败的重试只是浪费——要在"成功率提升"和"成本/风险"间取平衡。② 重试上限要可配,不同工具不同(查缓存 1 次、外部接口 5 次)。③ 即使有重试上限,也要有"持续失败熔断"——连续 N 次同错误直接停,不等耗尽次数。

九、Temporal 工作流视角(Java SDK,仅了解)

Temporal 是用"代码即工作流"实现可靠长流程的框架。它天然解决本节关心的三件事:

本节概念Temporal 对应
状态持久/可恢复Workflow 自动持久化每一步,崩溃后从事件重放恢复
超时/重试Activity 自带 ScheduleToClose / Heartbeat 超时 + RetryOptions(指数退避)
补偿(saga)手动写补偿 Activity,或用 Temporal 的补偿模式

Java SDK 示例(概念级,不必背):

@WorkflowInterface
public interface ClaimWorkflow {
  @WorkflowMethod
  String process(String claimId);
}
@ActivityInterface
public interface ClaimActivities {
  @ActivityMethod
  String submitClaim(String claimId);   // 失败按 RetryOptions 退避重试
}
仅作了解:Temporal 把"超时/重试/补偿/持久化"做成框架能力,Agent 长流程(如跨天理赔)可借助它获得企业级可靠性。面试能说出"它自动持久化+内置重试退避+支持补偿"即可,不必深入 API。
Temporal 是"代码即工作流"框架,自动持久化每步(可恢复)、Activity 自带超时+指数退避重试、支持补偿(saga)。它把本节三件事做成开箱能力,适合跨天长流程。了解即可。
① Temporal 是"替代/补充"Runtime 的方案之一,不是唯一答案——LangGraph 的持久化+重试也覆盖部分。面试别把 Temporal 当银弹。② 引入 Temporal 有运维成本(要跑 Temporal Server/Cluster),小场景不划算。③ 即使有 Temporal,业务补偿逻辑(怎么回滚理赔草稿)仍要自己写,框架只管"重试/持久化"不管"业务语义"。

十、资源与监控:重试/退避/补偿全留痕

记录项用途
每次重试(次数/间隔/原因)看是否频繁重试、退避是否生效
超时事件定位慢下游、定超时阈值
补偿触发(回滚/转人工)审计"为什么没办成"、复盘
熔断/限流触发发现下游不健康
重试次数、超时、补偿触发、熔断都要记 Trace——尤其"补偿转人工"最该记全,用于审计与下游健康度分析。
① 重试日志若不打原因,事后无法区分"网络抖"还是"下游挂",难优化。② 补偿转人工的工单要含完整上下文,否则人工接手成本极高、还可能二次出错。

十一、面试达标线①:重试 / 退避 / 补偿的设计

环节设计要点
重试只对瞬时错误重试(网络/429/偶发5xx);业务校验失败不重试,改输入或转人工;带幂等键
退避指数增长 + 上限 cap + 随机抖动;分散重试波避免同步风暴
补偿重试耗尽→回滚已做部分 / 标记人工介入 / 降级 PARTIAL / 幂等去重;高风险转人工留痕
配套退避+限流(控流)+熔断(断流)三重保护雪崩
核心:可重试看"是否瞬时";退避三件套(指数+上限+抖动);补偿把系统拉回一致(回滚/人工/降级/幂等);配合限流熔断防雪崩。

十二、面试达标线②:为什么不能无限重试、执行预算怎么和重试联动

无限重试代价:成本↑ + 延迟↑ + 雪崩下游 + 对业务错误无效 │ 必须有上限(次数 3–5 + 退避上限 + 预算上限) 重试消耗:次数 + token + 时间 │ 联动:每次重试前校验预算,超限即补偿/优雅结束
  1. 为什么不能无限重试:烧钱占资源、用户超时、持续打下游引发雪崩、对业务校验错误完全无效。
  2. 重试上限:MAX_RETRY(3–5)+ 退避上限 + 整体预算上限 + 持续失败熔断。
  3. 预算联动:重试计入次数/Token/时间预算;每次重试前统一校验预算,超限即进入补偿/优雅结束(PARTIAL),而非无脑重试。
  4. 平衡:在"成功率提升"和"成本/风险"间取平衡,及时认输转补偿/人工。

十三、W5D3 自测清单

  • 能说出单工具超时怎么设(不同工具不同超时),以及超时后为何要"取消底层请求 + 决定后续"。
  • 能区分单工具超时与整体 Agent 超时(时间预算)的层次关系。
  • 能列出"可重试 vs 不可重试"的错误分类,并解释为什么业务校验失败不能重试。
  • 能写出指数退避公式,并解释上限 cap 和抖动 jitter 各自的作用。
  • 能解释退避+抖动为什么能避免雪崩,以及限流/熔断的辅助作用。
  • 能说出补偿的几种动作(回滚/转人工/降级/幂等去重)及适用。
  • 能讲清重试如何消耗次数/Token/时间预算,为什么重试前要统一校验预算。
  • 能讲清为什么不能无限重试(成本/延迟/雪崩/无效),以及重试上限怎么设。
  • 能说出 Temporal 在超时/重试/补偿/持久化上的对应能力(了解级)。
  • 能讲清重试/退避/补偿的 Trace 该记什么,以及"补偿转人工"为何要带完整上下文。

十四、高频面试题速记卡

Q:哪些错误可以重试?
瞬时错误:网络超时、429 限流、偶发 5xx。业务校验失败(参数错/无权限/状态冲突)不可重试,要改输入或转人工。
Q:指数退避为什么要加抖动?
避免大量失败请求"同步"在同一时刻集体重试,把刚恢复的下游又打挂(重试风暴)。抖动把重试波摊平削峰。
Q:退避公式是什么?
sleep = base × 2^(attempt-1) + random(0, jitter),并设上限 cap(如 30s)。指数增长给下游恢复时间,上限防等太久。
Q:雪崩是什么,怎么防?
故障→大量同步重试→下游更慢→崩。退避+抖动削峰,限流控流,熔断断流,三重保护。
Q:重试耗尽后怎么补偿?
回滚已做部分 / 标记人工介入 / 降级返回 PARTIAL / 幂等去重。高风险(理赔提交失败)直接转人工并留痕。
Q:为什么不能无限重试?
成本爆炸、用户超时、持续打下游引发雪崩、且对业务错误完全无效。必须有限次+预算约束+耗尽转补偿。
Q:重试和执行预算怎么联动?
重试消耗次数+Token+时间三种预算;每次重试前统一校验预算,超限即进入补偿/优雅结束,而非无脑重试。
Q:单工具超时和整体超时什么关系?
单工具超时管一个下游调用(返回超时受控错误→重试/换路);整体超时(时间预算)管整个 Loop,更上层,超时中断循环优雅结束。
Q:补偿为什么也要幂等?
"回滚草稿"若被执行两次不能出错;且重试可能已部分成功,幂等去重防重复副作用(如重复提交理赔)。
Q:Temporal 和本节什么关系(了解)?
Temporal 把超时/重试退避/补偿/持久化做成框架能力:Workflow 自动持久化可恢复,Activity 自带超时+指数退避,支持 saga 补偿。适合跨天长流程。
FDE W5D3 学习手册 · 超时、重试与退避、补偿(面试级)· 配合《FDE-W5D3-评测题.md》自测 · 资源:Temporal Java SDK docs.temporal.io/develop/java、LangGraph BV1zKx4zWEZP
📌 待查★ 重要