数据任务怎么断点续传?游标保存了,为什么还是丢数或重复?
面试怎么回答
我会让游标表示连续已提交的数据边界,并明确它记录最后完成位置还是下一条待读位置。游标与结果能在同一事务里提交最好,跨系统则允许结果先提交、游标后推进,再依靠幂等承受重放。还要固定读取范围和确定性排序,处理同时间记录、部分页失败及并发完成乱序。恢复验收应主动在写入和保存游标之间制造失败,检查缺口、重复与最终结果。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
任务跑到第80页失败了,重启从第81页开始,看起来已经实现断点续传。可第80页到底是“请求成功”,还是“下游全部提交成功”?如果这个问题答不上来,断点只是一个数字,并不是可靠的恢复证据。
可恢复断点必须代表连续已提交的数据边界;先存游标会漏,后存游标会重,必须与提交和幂等一起设计。
先把“处理完成”拆成三步
获取到一页数据、完成转换、下游持久化成功,是三件不同的事。接口返回成功后立刻存下一页游标,不能证明这一页已经进入目标系统。
还要明确游标语义:保存的是最后一条已完成记录,还是下一条待处理记录?恢复时用大于还是大于等于,必须与这个定义匹配。
批次日志可以记录读取范围、结果数量、提交标识和游标,但日志本身也需要可靠保存。只有一条“处理成功”的文本,不足以判断部分数据是否已经落地。
两种先后顺序,各有一类风险
先保存游标,再提交结果,中间失败会跳过尚未完成的数据,造成缺口。后提交游标,如果结果已经成功而游标未更新,重启会再次处理同一范围。
跨系统难以原子提交时,通常更容易接受后者:允许可控重放,再用幂等写入或批次去重确保业务结果不会重复。
但“使用UPSERT”也不是完整答案。如果每次重放都是在旧值上加金额,或者顺带发送通知、调用扣款接口,重复执行仍有副作用。必须逐个定义幂等作用范围。
多个并发分页,不能取最大完成位置
假设第10页先完成,第9页仍在重试。如果把游标推进到10,恢复从11开始,第9页就可能永久缺失。
应该维护连续完成前沿,或者保存各分片独立状态及缺口集合。只有确认前面的范围都已经提交,才能推进共享的连续断点。
对于彼此独立的分片,可以每片保存游标,不必强行使用一个全局数字;但最终批次完成标记要等所有必需分片通过验收。
一个典型场景:最后一页只写了一半
比如一页100条记录分两批写目标库,第一批成功后第二批失败,任务却因分页请求成功而把游标提前存了。
最初怀疑接口分页丢数,重拉原页却能拿到完整100条。真正的问题是游标代表读取进度,不代表提交进度。旧测试只模拟整页请求失败,没有覆盖页内部分写入。
修复可以让整页结果与断点在同一目标事务内提交;如果做不到,就保留安全重放能力,并把部分成功记录的重复写入纳入幂等约束。
测试应分别在提交前、提交后但游标前、游标更新后以及并发页乱序完成时中断,再核对业务键覆盖,而不只是确认重启能继续打印日志。
读取范围不稳定,游标再准也会漂移
用页码加OFFSET扫描不断变化的源表,前面的插入或删除可能使后续页位置移动。恢复到原页码,不一定对应原来的业务记录。
可以依据源系统能力,采用快照、稳定分页令牌或确定性键集游标。用更新时间增量时,同一时间可能有多条记录,通常还需要唯一键作为第二排序条件。
同时固定本批高水位或范围上界,避免一边跑一边不断追逐新增数据。源端更正、删除和迟到变更如何纳入下一批,需要额外规则;一个游标不能自动捕获所有修改。
如果选择重叠回扫窗口,必须知道它只是覆盖某个迟到范围,不等于任意久远变更都不会漏。超过窗口的修订要有回补入口和对账发现机制。
这道题最值得讲清楚的是:断点不是“程序到了哪里”,而是“哪一段业务结果已经可靠完成,重复执行又会发生什么”。