4、批量数据源接入:HDFS / Hive 作为批量数据源、分区表设计、增量与全量策略
批量数据源接入,说白了就是解决「怎么把海量历史数据稳定、高效地拉进质量检测体系」的问题。
我这些年做数据治理,接触最多的批量源就是 HDFS 和 Hive。很多团队一上来就搞实时,结果发现离线数仓的脏数据能把实时链路也带偏。嗯,批量源的质量检测,其实是整个体系的基石。
4.1 HDFS 作为批量数据源:文件级别的质量关卡
HDFS 是底层存储。数据以文件形式存在,可能是 CSV、Parquet、ORC。我个人的习惯是,在接入层就做三道检查:
- 文件完整性:检查 _SUCCESS 标记文件是否存在,文件大小是否与预期一致。
- 元数据校验:文件名是否包含日期/批次号,目录结构是否符合约定。
- Schema 探测:读取前 N 行,验证字段数、数据类型是否匹配。
我的经验: 曾经有个项目,上游每天凌晨 3 点往 HDFS 写数据,但写入过程是「先写临时文件,再 rename」。我们直接读临时文件,导致数据不全。后来我加了一个「文件稳定期检测」——文件最后修改时间超过 10 分钟才认为写入完成。
4.2 Hive 作为批量数据源:表级别的质量防线
Hive 表比 HDFS 文件多了一层元数据。接入时,我重点关注三个维度:
| 维度 | 检测项 | 说明 |
|---|---|---|
| 表结构 | 字段名、类型、注释 | 与预期 Schema 做 diff,防止字段被误删或类型变更 |
| 分区信息 | 分区字段、分区值列表 | 检查是否有异常分区(如日期格式错误) |
| 数据量级 | 行数、存储大小 | 与历史均值对比,波动超过阈值则告警 |
你想想看,如果上游改了表结构,下游的 ETL 脚本直接崩掉。所以我在接入层会缓存一份「期望 Schema」,每次读取时做自动比对。
4.3 分区表设计:批量检测的命门
分区表设计得好不好,直接影响检测效率和资源消耗。我见过最糟糕的设计——按「省份+日期」双层分区,但省份字段是中文,导致 Hive 在底层生成大量目录,查询性能极差。
我的设计原则很简单:
- 时间分区优先:按日期或小时分区,这是增量检测的基础。
- 分区粒度适中:日分区是最常见的。小时分区适合数据量极大的场景,但管理成本也高。
- 避免过多层级:两层分区就够了,三层以上查询计划会变复杂。
推荐的分区结构:
其中 dt 是日期分区,biz_type 是业务类型分区。这样既能按天做增量检测,也能按业务类型做全量扫描。
dt=2024-01-01/biz_type=order其中 dt 是日期分区,biz_type 是业务类型分区。这样既能按天做增量检测,也能按业务类型做全量扫描。
4.4 增量与全量策略:什么时候用哪个?
这个问题,我每次培训都会被问到。其实选择很简单:
- 全量策略:首次接入、数据量小(百万级以下)、需要做历史数据回溯。
- 增量策略:日常检测、数据量大(亿级以上)、对时效性有要求。
但实际项目中,往往是混合使用。我举个例子:
某电商订单表,每天新增 500 万行。全量检测跑一次要 2 小时,太慢了。我的做法是:
- 每周日跑一次全量检测,做深度质量分析。
- 每天跑增量检测,只检测当天新增分区。
- 增量检测发现异常时,自动触发该分区的全量重检。
避坑指南: 我曾经在增量检测中只用了
WHERE dt = '${yesterday}',结果上游某天漏写了分区,导致当天数据全部丢失,但增量检测没报错,因为「没有数据」也被视为正常。后来我加了一条规则:如果检测到的行数为 0,必须告警。
4.5 核心流程:批量数据源接入质量检测
下面这张图,是我在多个项目中沉淀下来的接入检测流程。你可以直接拿去用。
4.6 代码示例:增量检测的 Hive SQL
这是我常用的增量检测模板。核心思路是:只扫描当天分区,避免全表扫描。
-- 增量检测:检查当天分区数据质量
SET hive.exec.dynamic.partition.mode = nonstrict;
INSERT OVERWRITE TABLE dwd_quality_check_result PARTITION (dt)
SELECT
'order' AS table_name,
dt,
COUNT(*) AS row_count,
COUNT(DISTINCT order_id) AS unique_orders,
SUM(CASE WHEN amount IS NULL THEN 1 ELSE 0 END) AS null_amount_cnt,
SUM(CASE WHEN status NOT IN ('paid','shipped','completed') THEN 1 ELSE 0 END) AS invalid_status_cnt
FROM ods_order
WHERE dt = '${yesterday}' -- 只扫当天分区
GROUP BY dt;
-- 结果判断:如果行数为 0 或异常率超过阈值,触发告警
SELECT
dt,
row_count,
unique_orders,
null_amount_cnt,
invalid_status_cnt,
CASE
WHEN row_count = 0 THEN 'ALERT: 无数据'
WHEN null_amount_cnt / row_count > 0.01 THEN 'ALERT: 金额空值率超过 1%'
WHEN invalid_status_cnt / row_count > 0.05 THEN 'ALERT: 状态异常率超过 5%'
ELSE 'PASS'
END AS check_result
FROM dwd_quality_check_result
WHERE dt = '${yesterday}';
小技巧: 增量检测的阈值不要写死。我习惯把阈值存在配置表里,比如
quality_config 表,每天动态读取。这样业务方可以自己调整,不用改代码。
4.7 全量检测的注意事项
全量检测虽然慢,但有些场景必须用。比如:
- 新接入的数据源,需要做一次全面的「数据体检」。
- 发现增量检测有异常,需要回溯历史数据找根因。
- 月底/年底的数据对账,需要全量比对。
做全量检测时,我建议:
- 分批次执行:按分区拆成多个任务,避免单任务 OOM。
- 结果增量写入:全量检测的结果表,按检测日期分区,不要覆盖历史。
- 设置超时机制:全量任务超过 4 小时自动 kill,防止阻塞其他任务。
我曾经踩过的坑: 有一次全量检测跑了一整天,结果发现是 Hive 表的小文件太多,导致 Map 阶段启动了几万个 Task。后来我在检测前加了一步「小文件合并」的预处理,全量检测时间从 6 小时降到了 40 分钟。
4.8 总结一下
批量数据源接入,核心就三件事:
- 文件/表级别的元数据校验——保证数据能读、结构对。
- 分区表设计——决定了检测效率和扩展性。
- 增量与全量策略——按场景选,别一刀切。
我个人觉得,批量接入的质量检测,做得好的话,能拦截掉 80% 以上的数据问题。剩下的 20%,交给实时链路去处理。这样分工,体系才稳。