1、重试策略概述:为什么需要重试?

大家好,我是老张。做 DevOps 这些年,我见过太多流水线因为一次网络抖动就全盘崩溃的场景。说实话,那种凌晨三点被报警叫醒,发现只是某个服务超时导致整个部署卡死的滋味,真不好受。

今天咱们聊聊重试策略。你可能觉得这玩意儿很简单——失败了就再试一次呗。但实际落地时,坑比你想的多得多。

1.1 为什么需要重试?

先问个问题:你的流水线真的可靠吗?

我敢打赌,大部分流水线里至少有一半的失败是暂时性故障。什么叫暂时性故障?就是那种过几秒再试一次就能成功的问题。比如:

  • 网络偶尔丢包,TCP 连接超时
  • 数据库连接池短暂打满
  • 下游服务刚好在做 GC,响应慢了 200ms
  • DNS 解析偶尔失败
  • 磁盘 IO 抖动导致文件写入失败

这些故障不是系统挂了,而是运气不好。你想想看,如果因为这种原因就让整个流水线失败,开发同学得重新触发构建,等个十几分钟甚至半小时,就为了等那个偶然的网络包重新传过来——这合理吗?

核心观点:重试不是掩盖问题,而是区分「暂时性故障」和「永久性故障」的第一道防线。

我在项目中遇到过最典型的例子:某次大促前,我们的部署流水线在拉取容器镜像时频繁超时。排查后发现是镜像仓库的 CDN 节点偶尔响应慢。加了一层重试后,成功率从 92% 直接飙到 99.8%。你看,问题本身没解决,但业务没受影响——这就是重试的价值。

1.2 重试的代价与收益分析

重试不是免费的午餐。每次重试都有成本,咱们得算清楚这笔账。

维度 收益 代价
可用性 提升流水线成功率 5%~30% 增加端到端延迟(每次重试多花几百毫秒到几秒)
运维成本 减少人工介入次数,降低 on-call 压力 需要设计重试逻辑,增加代码复杂度
资源消耗 避免因偶发故障导致的资源浪费(如已启动的构建环境) 重试本身消耗 CPU、内存、网络带宽
下游压力 无直接收益 可能放大请求量,导致下游雪崩

说白了,重试策略就是在可靠性和效率之间找平衡。你重试得越多,成功率越高,但延迟和资源消耗也越大。而且——嗯,这里要注意——不加节制的重试反而会害了你。

避坑指南:我曾经见过一个团队,给所有 API 调用都加了 5 次重试,间隔 0 秒。结果下游服务一次 GC 停顿,5 个重试请求同时打过去,直接把服务打挂了。这就是典型的「好心办坏事」。

所以,重试的代价不是线性的。当重试策略设计得不好时,代价会指数级上升。你需要考虑:

  • 重试次数:多少次合适?3 次是常见选择,但要看场景
  • 重试间隔:立即重试还是等一会儿?固定间隔还是递增?
  • 重试范围:所有失败都重试?还是只重试特定错误码?
  • 幂等性:重试会不会导致数据重复?

1.3 重试策略在流水线中的位置

咱们把流水线想象成一条生产线。每个环节都可能出问题,重试策略就像生产线上的「自动返工机制」。

来看一张图,你就明白了:

重试策略在流水线中的位置 代码检出 编译构建 单元测试 集成测试 部署上线 重试策略覆盖范围 失败 重试决策 重试执行 放弃/告警 关键决策点 • 是否达到最大重试次数? • 错误类型是否可重试? • 当前负载是否允许重试?

从图上你能看到,重试策略不是孤立的。它嵌在流水线的每个环节里。我个人习惯把重试策略放在两个地方:

  1. 任务级别:每个步骤内部的重试。比如编译失败时,自动重试一次。
  2. 流水线级别:整个流水线的重试。比如部署失败时,回滚后重新触发整个流水线。

你想想看,如果只在任务级别重试,那某个步骤连续失败 3 次后,流水线还是会挂。如果只在流水线级别重试,那每次重试都要从头跑一遍,浪费大量时间。所以,好的策略是分层重试:

实战建议:我在项目中通常这样设计——每个任务内部做 2 次快速重试(间隔 1 秒),如果还失败,交给流水线级别的重试(最多 1 次,间隔 30 秒)。这样既覆盖了偶发故障,又不会无限重试拖垮系统。

1.4 什么时候不该重试?

聊了这么多重试的好处,也得说说它的边界。有些情况,重试是火上浇油:

  • 4xx 错误:比如 401 未授权、403 禁止访问、404 不存在。这些错误重试一万次也没用,因为请求本身有问题。
  • 业务逻辑错误:比如参数校验失败、数据格式不对。重试不会改变输入数据。
  • 下游过载:如果下游已经返回 503 或超时,你再重试就是往火上浇油。这时候应该退避,甚至熔断。
  • 非幂等操作:比如创建订单、扣减库存。重试可能导致重复扣款或重复下单。

我记得有一次,某个支付服务因为数据库主从延迟,返回了 500 错误。我们的重试策略没做错误码过滤,结果 3 次重试都成功了——但每次成功都扣了一次钱。用户收到 4 条扣款短信,那场面……嗯,从那以后我就在重试逻辑里加了个「幂等性检查」的硬性要求。

1.5 重试策略的核心要素

总结一下,设计重试策略时,你需要回答这几个问题:

要素 说明 常见选择
重试条件 哪些错误值得重试? 5xx、网络超时、连接重置
最大次数 最多重试几次? 2~5 次,视场景而定
间隔策略 每次重试等多久? 固定间隔、指数退避、抖动
超时控制 单次重试的超时时间 比正常超时略短
熔断机制 连续失败多少次后停止重试? 结合断路器模式

说白了,重试策略就是一套规则引擎。它告诉你:什么时候该坚持,什么时候该放弃。后面几章我会详细拆解每个要素的具体实现,包括代码示例和配置模板。

最后说一句:重试不是银弹。它解决的是「偶发故障」,而不是「系统缺陷」。如果你的服务每 10 次请求就失败 5 次,别想着靠重试来救——先把根因找到再说。