技术2026 · 09 / 207 分钟♡ 47评论 9

断点续跑:一条流水线最值钱的不是快,是能从第 137 步接着走

一次跑三小时的任务在第 137 步失败,重跑要三小时还是三十秒,差别不在算力,在你有没有从第一天就为「失败」设计。

深夜的生产线 · 三块屏都在跑

产线刚搭起来那几个月,我最怕的不是失败,是失败之后要从头再来。

一条成片三小时,第 137 步挂了——可能是显存、可能是下游超时、可能只是磁盘满了——然后前面 136 步的成果全部作废,从零开始。

那段时间我做过最蠢的事,是给整条产线加了一个「总重试」:失败就整个重来。结果是同一个任务连续重来三次,每次都在同一个地方挂,浪费了九个小时才发现是一个必然失败的输入。

后来我把「失败」当成产线的一等公民来设计,下面是几条最有用的原则。

每一步的产物都落盘,而且命名要能推出「是哪一步、给哪个输入」

这是断点续跑的地基。听起来理所当然,但很多产线在早期为了省事,中间产物只存在内存里,或者用时间戳命名——跑完之后根本对不上哪个文件属于哪一步。

我最后用的命名规则很朴素:<任务ID>/<步骤序号>-<步骤名>.<扩展名>。看到目录就知道跑到了哪一步、缺了哪一步。

顺带解决了一个隐蔽的问题:并发跑多个任务时,随机命名会让你完全无法反推哪份产物属于哪个任务。每个任务一个独立目录,零竞态。

续跑的前提是幂等:同一步跑两次,结果必须一样

有了落盘的产物,续跑逻辑就很简单:跑之前先看这一步的产物在不在,在就跳过。

但这要求每一步都是幂等的——给同样的输入,产出同样的结果,不依赖「上一次跑到哪」这种隐藏状态。

我踩过的坑是一个「追加写入」的步骤:它往一个文件末尾追加内容,重跑一次就追加两遍。改成「先写临时文件,成功后原子替换」之后才真正幂等。

任何不幂等的步骤都是断点续跑的漏洞,续跑到它那里就会产出错误结果,而且不报错。

把失败分成三类,各走各的路

不是所有失败都该重试。我最后分成三类:

区分的依据是错误类型和错误原文。这要求每一步失败时把原始错误完整保留下来,不要包装成一句「处理失败」——我曾经因为一层包装把真正的根因截掉,对着「处理失败」四个字排查了一整晚。

然后才是「快」

做完上面三件事,我才回头去优化速度。

原因很简单:一条能从第 137 步接着走的产线,失败一次的代价是几十秒;一条每次失败都从头再来的产线,就算快一倍,失败一次的代价还是三小时。可靠性带来的时间收益,比任何单点优化都大。

现在这条产线跑一次仍然要两个多小时。但过去半年它的重跑总时长,加起来不到一个下午。


有朋友问过我,这套东西是不是过度设计。

我的答案是:如果一条产线一辈子只跑一次,是的。但只要它会跑第二次,「能从哪里接着走」就是它最值钱的能力,没有之一。

这篇里的照片Frames全部相册 →
想不通就摊开纸画,画到第三版才对
想不通就摊开纸画,画到第三版才对家 · 书桌 · Sony A7C II · 50mm 微距
← 更早一篇
日志里什么都看不出来的故障,我是怎么查的

关注公众号「十年追随」

新文章第一时间推给你。留言我都会回,公众号里也能收到回复通知。 不发广告,一周最多两条。

十年追随 公众号二维码
评论Comments9 条 · 匿名也能评,昵称头像会记住
评论服务(Waline)待部署 —— 香港 VPS 起来后填 SERVICES.waline 即生效。
想说话可以先去 留言板,那边我每条都回。
关注公众号「十年追随」更新第一时间推给你 · 留言也能收到我的回复
看二维码