考察点
回刷补数是数仓工程师的日常高危操作,这道题直接考你闯没闯过祸。面试官想听到:回刷场景的分类、全量重刷和增量补数怎么选、怎么保证不污染线上正在用的数据、下游怎么联动。追问常落在幂等设计和「刷错了怎么救」。
参考答案
先分清场景
回刷补数不是一件事,是四类:
- 口径变更:业务改了指标定义(比如「有效订单」从含预售改为不含预售),需要按新口径重算历史,影响面通常最大。
- 故障补数:上游断流、任务失败导致某天分区缺失或数据不全,恢复后把缺的补回来,范围明确。
- 脏数据修复:源系统数据错了后来修正(订单状态回传错误),数仓跟着重刷受影响的行。
- 历史初始化:新业务接入、新表上线,需要回填过去 N 个月的数据。
不同场景的范围、紧急度和风险完全不同,混在一起谈「回刷」没有章法。
全量重刷还是增量补数
判断依据三条:
- 变更的影响范围。口径变更如果只影响某几行(比如某类订单状态),按条件刷增量分区即可;如果是度量逻辑本身变了(金额计算方式改了),通常要全量重刷所有历史分区。
- 数据源的有效期。日志类数据可能只保留 90 天,业务库 binlog 只留 7 天——想刷一年前的数据,源都没了,只能从 ODS 快照或归档恢复,这条直接决定方案可行性,先查再定方案。
- 成本。一张 10 亿行的表全量重刷可能要跑几个小时、占大量资源;能按分区增量刷就别全量。
安全回刷的标准动作
第一,所有任务必须幂等。产出用 insert overwrite partition 按分区覆盖,重跑多少次结果都一样;绝对不用 insert into 追加,失败重试一次数据就翻倍。这是补数能放心做的前提,新表评审就该卡住。
第二,影响面评估靠血缘。刷一张 DWS 表之前,先把下游所有依赖表拉出来——它们的数据也是错的,要么跟着重刷,要么确认下游自己会重算。只刷源头不刷下游,等于口径分裂。
第三,影子表/双跑切换保安全。大口径变更不要直接覆盖线上表:先建影子表按新口径重跑,与旧表双跑对比差异(差异是否符合预期、差异率多少),业务方确认后,再通过视图或表名切换把流量切过去。出问题一键切回。直接在原表上 overwrite,刷错了连后悔药都没有。
第四,与正常调度隔离。回刷任务打独立资源队列(Yarn 队列或 K8s namespace),避免把凌晨正常批产挤垮;和正常任务设互斥——今天的分区正在被日常调度写,你又去 overwrite 同一分区,必出脏数据。大回刷放在业务低峰、分批跑(比如一次刷一个月,跑完校验再刷下一个月),不要一口气提交 365 个分区任务。
第五,刷完要验证。行数对比、关键指标与旧值/对账源比对、抽样业务核对,三步都过了才算完。
刷错了怎么救
事前预防的成本远低于事后救火:覆盖式回刷前对目标分区做快照备份(create table xxx_bak_20260803 as select,或开表格式的时间旅行能力,Hudi/Iceberg 天然支持回滚);真刷错了,有备份就回滚,没备份只能找上游源数据重跑——这又回到为什么 ODS 原始数据要长期保留、为什么任务必须幂等。
可能的追问
- 下游有几十张表都要跟着刷,怎么组织? 按血缘分层排好依赖顺序,用调度系统的补数据功能(DolphinScheduler/Airflow 都支持按 DAG 补历史实例)批量触发,让调度器按依赖关系自己排,别手工一张张跑。
- 口径变更后历史一定要全刷吗? 不一定,跟业务方确认:很多场景只刷近一年,更早的保留旧口径并在元数据标注「2025-08 前为旧口径」,报表口径突变给业务带来的困扰可能大于口径统一的收益。
- 实时链路怎么补数? 两条路:Kafka 回放(在保留期内,从指定位点重消费);超出保留期就走离线修正——批任务重算后覆盖 OLAP 表对应分区,这也是为什么实时数仓仍需保留离线修正能力。