假如你是一家餐厅的后厨总管。某天晚上盘点时你发现,上周四的订单记录一团糟——那天下班前记录员临时请假,好几桌顾客的菜根本没进台账。顾客当时吃得很满意,可台账就是差着一截。怎么办?只能让厨师照着原始菜谱,把那几天的菜重新做一遍、重新补记到账上。在数据世界里,这个“重新补做历史订单”的动作,就叫回填(Backfill)。 数据管道就像后厨流水线:数据源是食材仓库,处理逻辑是菜谱,目标表是上菜的餐桌。当历史某个时间段的数据缺失、损坏,或者菜谱规则变了(业务口径调整),就需要对这一段历史数据重新跑一遍管道,把结果补齐、修正。这篇文章会全程用“后厨补菜”这个比喻,带你理解回填策略的方方面面:回填范围怎么定、并发怎么控、怎么保证重复炒菜不会多上一份、怎么确认菜没做错、怎么省钱、失败之后又该怎么办。

岗位关联

掌握数据管道回填策略,是数据工程师在管道事故、口径变更、历史数据倒灌等高频场景下稳住局面、保障数据可信的核心能力,也是数据工程面试的高频考察点。

目录
  1. 可视化演示
  2. 回填基础概念
  3. 回填范围确定
  4. 调度执行设计
  5. 幂等保障机制
  6. 验证比对机制
  7. 成本水位控制
  8. 失败恢复策略
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示数据管道回填的范围界定、幂等性保障与资源调度竞争治理,通过模式切换理解历史数据重跑的核心工程机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

回填范围:从变更点追溯受影响时间窗口 增量处理面向当日新增,回填面向历史数据以新逻辑重跑 范围过大浪费资源,过小遗漏受影响数据,需精确界定 Backfill(t1, t2) = Replay(pipeline, t1→t2) 回填是数据管道可重放性的直接体现

回填基础概念

周四漏掉的订单,顾客不会因为“系统坏了”就原谅你,账目必须补齐。补做之前,后厨得先搞清楚:缺的是哪几天、哪些桌的菜、一共要补多少道。在数据世界里,回填指的就是对历史某个时间范围内的数据,重新执行一遍数据处理管道,把缺失或错误的结果补齐、修正。它和日常的“增量调度”是两回事:增量管的是“新来的数据”,回填管的是“过去欠下的账”。

哪些情况需要回填?最常见的有四类:上游源系统宕机导致某几天数据缺失;数据管道本身有 bug 导致部分分区结果错误;业务口径调整,比如“活跃用户”从“登录”改为“登录 + 有效点击”,历史指标全部失效;以及新数仓初建时把近一两年的历史数据倒灌进来。触发回填后,第一步是估工作量——要补多少分区、多少条数据、管道跑多快。

回填任务量的估算公式很简单:

把后厨放回数据世界:回填不是随手点个“重跑”按钮,它需要像后厨盘点一样先厘清“欠了多少账”。账目清,策略才有意义。

T=N×VRT = \frac{N \times V}{R}
前面忙活半天,其实就想回答一个问题:这顿“补菜”要花多少时间?分区数 × 单分区数据量 ÷ 管道吞吐,就是预计总耗时。
  1. N(分区数量)需要回填的时间分区个数,天级管道回填 7 天就是 7 个分区。
    NN
  2. V(单分区体量)每个分区平均的数据条数,比如每天 500 万条。
    VV
  3. R(管道吞吐)管道单位时间能处理的数据量,取决于计算引擎规格和 SQL 复杂度。
    RR
  4. T(预计耗时)三者相除即预计回填总耗时,超时太久就该考虑加资源或分批补。
    N×VR\frac{N \times V}{R}

回填范围确定

餐馆要补菜,第一件事不是开火,而是翻订单找答案:到底缺哪几天的菜、涉及哪几桌、有没有哪道菜还依赖其他菜才能做。范围找错了,要么补错,要么补漏。数据管道回填也一样,启动前必须把回填范围钉死:从哪天到哪天、涉及哪些数据分区、下游还有哪些表依赖这些数据。

数据按时间存储在表里,每个时间段是一个“分区”,就像后厨按日期归档的订单夹。第一步是确定时间窗口——起始时间 S 和结束时间 E。第二步是定位分区:天级管道下,窗口内每一天对应一个分区,例如 dt=2024-03-10。第三步是依赖分析:哪些下游表由这份数据产出,回填是否会计联触发它们的重算。范围定得越精确,后面每一步的代价就越小。

计算窗口内分区数的公式:

范围,就是后厨的“补菜清单”。没有清单,厨师只能凭感觉开火;有了清单,每一道补菜都有的放矢。

Nw=⌈E−SΔt⌉+1N_w = \left\lceil \frac{E - S}{\Delta t} \right\rceil + 1
这个公式把“大概三月初到四月初”这种模糊感觉,换算成“一共要补 29 个分区”的精确数字,避免漏补或白补。
  1. S(窗口起点)回填数据的最早时间,例如 2024-03-01 00:00:00。
    SS
  2. E(窗口终点)回填数据的最晚时间,例如 2024-03-29 23:59:59。
    EE
  3. Δt(分区粒度)一个分区的时长,天级管道就是 1 天。
    Δt\Delta t
  4. N_w(窗口分区数)窗口时长除以粒度后向上取整再加 1,得到窗口内全部分区数,用来和实际缺失清单互相印证。
    ⌈E−SΔt⌉+1\left\lceil \frac{E - S}{\Delta t} \right\rceil + 1

调度执行设计

后厨补菜最怕什么?怕补菜把晚饭高峰的灶台全占了,正常营业停摆。有经验的厨师长会这样安排:先看现在有几口空锅,再决定一轮最多同时炒几道;把客人催得最急的菜往前排;补菜尽量放在下午空闲时段。回填调度设计的核心也是这三件事:并发控制、优先级、错峰隔离。

先说并发控制。回填任务非常消耗资源,如果一股脑把几十个分区同时丢进集群,在线实时任务会被挤压到超时。设计上要给回填单独设置并发上限,把任务放进独立队列,并限制其最多占用的资源。然后是优先级排序:直接影响线上报表和模型训练的“热数据”先回填,长尾历史数据后补。最后是错峰隔离:回填调度尽量放在凌晨低峰,并与在线任务做资源池隔离。

并发度如何合理设定?可以参照:

并发调度就像后厨排灶:锅是有限的,菜是批量的。排得科学,补菜不耽误营业;排得随意,正常生意都受影响。

C=min⁡(Cmax⁡, ⌈Nk⌉)C = \min\left(C_{\max},\ \left\lceil \frac{N}{k} \right\rceil\right)
简单说:既不要少到跑不完,也不要多到撑爆集群。在“任务需要”和“系统安全”之间取最小值。
  1. N(待回填分区数)本次回填总共要处理的分区数,来自范围确定环节。
    NN
  2. k(单任务分区数)一个执行任务能承载的分区数,一般取 2~8,视单分区体量而定。
    kk
  3. Cmax(安全并发上限)集群为回填预留的最大并发数,防止挤占在线任务。
    Cmax⁡C_{\max}
  4. C(实际并发度)向上取整算出任务需求后,与安全上限取最小值,既避免浪费也不超载。
    min⁡(Cmax⁡, ⌈Nk⌉)\min\left(C_{\max},\ \left\lceil \frac{N}{k} \right\rceil\right)

幂等保障机制

后厨最容易犯的错:顾客催菜,厨师心里打鼓“这道菜我是不是做过了?”于是又炒了一份,结果同一桌上了两份。避免这种乌龙,后厨需要“记菜牌”——做没做过,以牌子为准。数据回填里的“记菜牌”思想,就叫幂等性:同一个回填任务,无论执行一遍还是两遍,最终写入目标表的数据结果完全一致,绝不重复。

为什么幂等是回填的生命线?因为回填天然会重复执行:第一次跑一半失败,重试要再跑一遍;验证不满意,修完逻辑又要跑一遍。如果每次执行都往表里插一份数据,行数越跑越多,所有指标都会偏移。做到幂等,最常用的是分区覆盖写入:目标表按日期分区,回填时直接重写整个分区而不是追加插入;其次是唯一键去重,写入前按主键过滤已存在的记录;第三是“全量重算替代增量合并”,干脆不用 upsert,直接把整个分区重算。

验证幂等是否成立,可以把同一分区连续跑两次并对比:

幂等的价值就像“记菜牌”:同一个菜做几遍都行,但端上桌的永远只有一份。数据只有这样,才敢放心地反复重算。

count(S1)=count(S2),sum(A1)=sum(A2)\text{count}(S_1) = \text{count}(S_2),\quad \text{sum}(A_1) = \text{sum}(A_2)
同一道菜上桌两次但数量不多不少——第一次记 100 行,第二次还是 100 行,关键指标求和也对得上,幂等成立。
  1. count(S1)第一次回填写入目标分区的总行数。
    count(S1)\text{count}(S_1)
  2. count(S2)第二次重跑后的总行数,两者相等说明没有重复写入。
    count(S2)\text{count}(S_2)
  3. sum(A1) = sum(A2)数值列两次求和结果一致,说明没有因重复执行带来数值漂移。
    sum(A1)=sum(A2)\text{sum}(A_1) = \text{sum}(A_2)

验证比对机制

菜做完了,不能直接端给客人。服务员要拿着订单核对:菜名对吗?数量够吗?有没有把葱油面做成炸酱面?回填也一样,跑完不等于成功,必须验证通过才能宣布完成。验证比对机制就是回填端到桌前的那道关卡。

最基础的验证是行数核对:比对源表和目标表同一分区的记录数是否一致,还可以比对关键列的求和值(比如订单金额合计)有没有漂移。更细的验证是抽样比对:随机抽取分区里的若干条记录,逐字段比较源与目标的数据。最后是质量门槛:定义一组规则,比如“行数落差 < 1%”“空值率 < 5%”,全部通过才允许对外发布数据,任何一条不满足就触发重算或告警。

抽样验证时,样本量可以用如下公式估算:

验证环节就像上菜前的最后核对:它决定一份回填结果是“可以见客”还是“退回重做”。没有验证的回填,就像不核对订单就上菜,迟早要出乱子。

n=N1+N×e2n = \frac{N}{1 + N \times e^2}
不需要把 1 亿行全部检查一遍,按公式抽一个适当的样本,就能高置信度地判断“这锅菜有没有问题”。
  1. N(分区总行数)待验证分区的全量记录数。
    NN
  2. e(允许误差)抽样允许的误差率,常见取 0.05。
    ee
  3. n(抽样行数)最少应抽的行数,在这 n 行上做逐字段比对。
    nn
  4. 趋近性质N 很大时 n 趋近于 1/e²,说明抽样能以极小成本支撑整体判断。
    N1+N×e2\frac{N}{1 + N \times e^2}

成本水位控制

补菜不是不计代价地开火。后厨会精打细算:燃气、人力、食材都要花钱,一周的预算不能一天烧光。常见的做法是分批炒——先把客人最急的几道补上,其余的慢慢排;还要选在闲时开火,燃气费更划算。数据回填的成本控制逻辑与此完全一致。

回填的成本主要由三块构成:占用的计算核数、运行的小时数、单位核时的价格。控制手段有三个方向:其一,分批回填,把大窗口切成多个小批次,逐批提交而不是一次性全量压上;其二,错峰降级,把回填安排到业务低峰,并用低优先级队列给在线任务让位;其三,如果下游只关心聚合结果,先回填高优聚合层,明细层放到最后,必要时压缩中间态数据来省 IO。

回填的资源成本可以预先估算:

成本控制不是“小气”,而是后厨的生意经:预算有限,补菜更要排优先级、分批次、选时机,让每一勺燃气都烧在刀刃上。

Cost=C×P×H×price\text{Cost} = C \times P \times H \times \text{price}
一句话:花多少钱取决于开几口锅、每口锅多猛、烧多久。算出预算后,再决定要不要分批、要不要降级。
  1. C(并发任务数)同时运行的回填任务个数。
    CC
  2. P(单任务核数)平均每个任务申请的 CPU 核数。
    PP
  3. H(回填时长)整批回填预计的时钟小时数。
    HH
  4. price(核时单价)单位核时的资源成本,四者相乘即总成本。
    Cost=C×P×H×price\text{Cost} = C \times P \times H \times \text{price}

失败恢复策略

厨师炒菜也有失手的时候。火大了、锅糊了,怎么办?第一选择是倒掉重炒一遍,这就是重试;如果连着重试都失败,不能再硬冲了,要关火排查原因;最怕的是之前端上桌的菜其实也有问题,那就得撤回来重做。回填的失败恢复策略,就是这套兜底机制。

断点续跑是最实用的恢复手段:每完成一个分区就在状态表里记下“已完成”,失败时重跑只需从失败分区继续,而不是从头再来。自动重试要讲究节奏:连续失败说明系统可能还没恢复,立刻高频重试只会雪上加霜,因此采用指数退避——间隔越拉越长。一旦重试次数超过阈值,立刻触发告警升级。最后是快速回滚:回填先写入临时表,验证全部通过后再原子切换正式分区;一旦失败,随时可切回旧数据,业务无感。

重试等待间隔的公式:

失败恢复是回填的最后防线:允许失败,但绝不允许“带着伤还硬冲”,更不允许“跑半截没人管”。有了断点、退避和回滚,后厨才能做到:菜糊了不可怕,怕的是连重炒的章法都没有。

tk=t0×2kt_k = t_0 \times 2^k
第一次失败等 1 秒,第二次等 2 秒,第三次等 4 秒……像冷静下来深呼吸,而不是疯狂砸门。
  1. t0(初始等待)第一次失败后的等待秒数,建议配置 1~5 秒。
    t0t_0
  2. k(失败次数)同一分区连续失败的累计次数。
    kk
  3. tk(本次等待)第 k 次重试前的等待时长,失败越多等待越长。
    t0×2kt_0 \times 2^k

AI 应用场景

数仓初建时的历史数据倒灌

阶段:数据接入与建模

解决的问题:新数仓上线时往往只有当前快照,没有历史数据,AI 模型的特征工程、趋势分析无从做起。传统做法是人工写临时脚本复制数据,容易漏分区、无法重试。用回填策略把近一年的源日志按日分区倒灌进数仓,全程可监控、可断点续跑。

具体案例:某推荐团队搭建新特征平台,需要 90 天用户行为序列。数据工程师通过回填任务把 Kafka 中近 90 天事件按 dt 分区重放至对象存储,调度 6 个并发任务,约 12 小时完成,验证行数一致后对外发布。

指标口径变更后的全量重算

阶段:特征工程与指标加工

解决的问题:业务方把“活跃用户”从“登录”改为“登录 + 有效点击”,口径一变,历史指标全部失效。手工改 SQL 再逐天重跑不现实,回填策略按新口径重算过去 90 天的每日汇总表,并通过临时表切换实现无感更新。

具体案例:广告效果报表口径调整,数据分析师配合数据工程师对 90 天聚合表做分区覆盖回填,先写临时表验证、再原子切换分区,报表侧无需停机即可看到修正后的历史曲线。

上游补偿数据驱动管道重跑

阶段:数据质量保障

解决的问题:上游业务库宕机导致当天数据少了一批,源系统修复后补齐了缺失记录。如果下游管道不感知,特征表就会永久缺一段。回填策略让管道监听“上游补偿完成”事件,自动对受影响分区发起回填。

具体案例:交易系统机房故障后补偿了 3 小时交易流水,风控模型的数据管道收到补偿通知后,自动回填这 3 小时的实时特征表,并在验证通过后恢复在线写入,风控监控指标未出现断层。

Python 演示

python78 行
# -*- coding: utf-8 -*-"""Backfill strategy simulator: scope, idempotency, verify, retry."""import randomimport time  class BackfillJob:    """One backfill task for a single time partition."""     def __init__(self, partition, rows, checksum):        self.partition = partition        self.rows = rows        self.source_checksum = checksum        self.sink_checksum = None        self.status = "pending"        self.retries = 0     def run_once(self):        self.status = "running"        time.sleep(0.02)        ok = random.random() < 0.85        if ok:            self.sink_checksum = self.source_checksum            self.status = "success"        else:            self.retries += 1            self.status = "failed"        return self.status     def is_stable(self):        return (self.status == "success" and                self.sink_checksum == self.source_checksum)  def verify_partition(job):    """Idempotency check: result must match source checksum."""    if job.status != "success":        return False    if job.sink_checksum != job.source_checksum:        return False    return True  def backfill_pipeline(partitions, max_retries=3, wait_base=0.1):    """Run backfill partition by partition with exponential backoff."""    results = []    for name, rows, checksum in partitions:        job = BackfillJob(name, rows, checksum)        gap = wait_base        for attempt in range(max_retries + 1):            job.run_once()            if verify_partition(job):                results.append((name, "success", attempt))                break            time.sleep(gap)            gap *= 2        else:            results.append((name, "failed", max_retries))    return results  def main():    partitions = [        ("2024-03-01", 1000, 1000),        ("2024-03-02", 2000, 2000),        ("2024-03-03", 3000, 3000),        ("2024-03-04", 4000, 4000),        ("2024-03-05", 5000, 5000),        ("2024-03-06", 6000, 6000),        ("2024-03-07", 7000, 7000),    ]    print("backfill 7 historical partitions...(85% success rate)")    for name, status, attempt in backfill_pipeline(partitions):        print(f"[{name}] {status} (retry {attempt})")  if __name__ == "__main__":    main()
目的:用一个小型模拟器演示回填任务逐分区执行、校验比对、失败重试与指数退避的完整流程,帮助理解回填策略在真实调度系统中的落地逻辑。
  1. job.run_once()模拟一次回填执行,相当于厨师按菜谱炒一道菜。
  2. ok = random.random() < 0.85模拟 85% 成功率,还原“有些菜第一次会做失败”的真实情况。
  3. verify_partition(job)上菜前核对:校验和一致才算真正完成。
  4. gap *= 2指数退避:连续失败就加倍等待,避免把后厨挤爆。
  5. backfill_pipeline(partitions, max_retries=3, wait_base=0.1)逐分区回填,像按时间顺序补做一道道菜。

常见误区

误区我以为回填就是手动重新点一遍“运行”按钮,让管道把当前数据重新处理一遍,任务结束就算回填完成。

正解回填是针对历史缺失窗口的专项重跑,必须确定范围、保证幂等覆盖写入、验证结果。如果不加覆盖直接重跑,很可能会在目标表追加出重复数据,就像同一道菜没看记菜牌就端了两份上桌。

为何常见:日常重启任务太常见,容易把“重跑一次”误当成回填的全部,忽略了回填对正确性的额外要求。

误区回填时间窗口我一般凭经验,感觉“这周的数据可能有点问题”,就直接前后多拉几天一起补,宽覆盖总比漏补好。

正解范围过宽会导致巨额资源浪费,过窄则补不完整。正确做法是先核对上游变更记录,用分区缺失清单定位受影响窗口,再用窗口分区数公式验证覆盖完整性。像后厨补菜必须先翻订单,不能凭感觉开火。

为何常见:历史数据看不到边界,直觉最省事,但代价往往在回填完成后才发现——要么白烧了钱,要么账还是对不上。

误区我更新了管道逻辑,觉得它会自动把以前算错的历史数据修正,在线跑几天应该就正常了。

正解增量管道只处理新到的事件,历史分区已经固化,不会随新逻辑自动重算。必须显式发起回填,按新口径重写受影响分区,历史数据才会被修正。这就像改了菜谱,已经端上桌的旧菜不会自己变新。

为何常见:在线管道给人“一直在运行”的错觉,让人忽略了历史数据并不会自愈。

误区回填慢就加并发,把集群几千核全部怼给回填任务,反正只是补数据,越猛越快。

正解并发过大会抢占在线任务资源,导致线上 SLA 受损;同时资源竞争激烈时任务失败率上升、重试暴涨,回填反而更慢。正确做法是设安全并发上限、独立资源池,让回填与在线任务隔离。

为何常见:局部思维只看见回填任务本身,没看见集群里还有在线业务在共享资源。就像补菜把灶台全占了,晚市正常营业直接停摆。

误区回填任务全部显示成功,我就直接发公告说数据已修复,结果分析师一查数值根本对不上。

正解任务“成功”只代表管道退出码为 0,不代表数据正确。必须做行数核对、抽样比对、质量门槛验证,全部通过后才能对外发布。像服务员上菜前必须核对订单,不能因为后厨喊了句“好了”就直接端走。

为何常见:任务状态面板让人过度信任“绿色即代表成功”,忘了数据正确性需要额外的验证流程来兜底。

面试题

Q1. 数据管道回填最准确的定义是什么?

单选题 · easy

  • A.重跑一次当前全部任务
  • B.对历史窗口重跑以补齐结果← 正确答案
  • C.每天定时执行管道任务
  • D.删除历史数据以节省存储

答案:B。回填针对历史时间窗口缺失或错误的数据进行重新计算,B 正确。A 忽略“历史窗口”这个关键限定;C 是日常调度;D 是删数操作。就像补菜只补漏掉的订单,而不是重做所有菜。

Q2. 以下哪种情况最常触发回填?

单选题 · easy

  • A.管道运行速度明显变慢
  • B.指标口径调整需重算历史← 正确答案
  • C.目标表存储空间不足
  • D.新员工刚入职需要培训

答案:B。口径调整意味着历史结果全部不符合新口径,只能回填重算。A 是性能问题,C 是容量问题,D 与数据无关。这就像菜谱改了,之前端出去的菜都得按新菜谱重做。

Q3. 确定回填范围的核心步骤是什么?

单选题 · mid

  • A.随便选一段时间先试跑
  • B.界定窗口并定位受影响分区← 正确答案
  • C.直接全量回填所有历史
  • D.只回填最近一天的数据

答案:B。回填范围要清晰界定时间窗口,并定位受影响分区及其依赖,B 正确。全量回填代价巨大;随意选段容易漏补;只补最近一天可能连不上依赖。先清账再开火,是后厨的铁律。

Q4. 幂等写入的主要目标是什么?

单选题 · mid

  • A.让回填任务运行更快
  • B.让重复执行结果保持一致← 正确答案
  • C.减少代码量便于维护
  • D.提升集群的总核心数

答案:B。幂等要求同一任务无论执行多少次,结果都一致,不产生重复数据,B 正确。它不追求速度或代码量,更与核数无关。就像同一道菜做五遍,端上桌的永远只能有一份。

Q5. 回填后最基础的验证手段是什么?

单选题 · mid

  • A.源表与目标表行数校验一致← 正确答案
  • B.检查任务日志是否完整
  • C.人工抽查一条数据即可
  • D.查看集群 CPU 使用率

答案:A。行数一致是回填成功的最基本信号,A 正确。日志完整只代表执行过程没断;抽查一条代表性不足;CPU 高低与数据正确性无关。上菜前先数一数碗筷数量齐不齐,是第一步。

Q6. 下列哪些做法能保障回填幂等?

多选题 · mid

  • A.按分区覆盖式写入← 正确答案
  • B.写入前按主键去重← 正确答案
  • C.随机采样后部分写入
  • D.全量重算替代增量合并← 正确答案

答案:ABD。覆盖写入、主键去重、全量重算都是保障幂等的经典手段。随机采样写入会丢数据,结果不一致。幂等就是怎么重复都不会多出一份数据,像记菜牌一样可靠。

Q7. 回填失败后用指数退避重试的核心理由是什么?

单选题 · mid

  • A.显著增加任务重试次数
  • B.避免故障期高频冲击系统← 正确答案
  • C.提高最终的数据准确率
  • D.让回填日志更易阅读

答案:B。指数退避让重试间隔逐渐拉长,防止故障未恢复时系统被反复冲击,B 正确。它不提高准确率,也不服务日志。就像敲门没人应,越敲越快只会更糟,应该越等越久再试。

Q8. 哪些措施能有效控制回填成本?

多选题 · hard

  • A.分阶段切片分步执行← 正确答案
  • B.错峰调度避开业务高峰← 正确答案
  • C.无条件拉满全部并发
  • D.先补高优聚合层再补明细← 正确答案

答案:ABD。分批执行、错峰调度、先优后细都能降低瞬时资源峰值和总体成本。C 会挤占在线资源,反而抬高整体代价。省钱不靠蛮力,靠的是排兵布阵。

Q9. 回填结果如何做到快速回滚?

单选题 · hard

  • A.直接在目标表改写并记旧值
  • B.先写临时表验证后原子切换← 正确答案
  • C.回填前备份整个数据库
  • D.失败恢复时重启整个管道

答案:B。先写临时表、验证通过后原子切换分区,能在验证失败时立刻切回旧数据,B 正确。备份整个数据库代价大且切换慢;直接改写旧值难以恢复。菜先盛到备用盘里,确认没问题再端上桌。

Q10. 断点续跑方案的优势有哪些?

多选题 · hard

  • A.从失败分区续跑避免重复劳动← 正确答案
  • B.只增补未完成分区节约资源← 正确答案
  • C.不再需要任何失败重试
  • D.无需记录任何元数据信息

答案:AB。断点续跑会记录已完成分区,失败后从断点继续,既省资源又避免重复计算。但它仍需要重试机制,也必须记录元数据,因此 C、D 错误。回填像一本记账本,记到哪补到哪,账本本身不可省。