ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ETL全量与增量选型指南:数据采集、同步、Cube构建与备份的避坑实践

ETL全量与增量选型指南:数据采集、同步、Cube构建与备份的避坑实践 简介这份PDF资料围绕ETL中的全量与增量策略展开面向数据仓库、大数据开发及数据同步方向的初中级工程师帮助厘清两种抽取方式在采集、同步、构建与备份等场景下的差异与取舍。资源包内含1个PDF文件大小约79KB篇幅精炼便于快速通读与查阅。目前已有3390人学习下载具备一定的参考热度。内容从数据采集切入对比全量抽取简单但数据量大、增量抽取复杂但压力更小的特点并延伸至数据同步中全量覆盖、异步写与物理删除的隐患以及增量同步长期易引发的一致性风险同时涉及Cube全量构建与增量构建在计算量、Segment合并及查询性能上的区别以及全量备份、增量备份与差异备份在速度、恢复和磁盘空间上的权衡。读者可借此建立全量与增量策略的选型框架理解日志文件、时间戳等变更追踪手段的适用边界为实际ETL方案设计提供判断依据。1. 全量与增量为什么你每次跑完 ETL 都觉得数据“对不上”凌晨两点调度器准时拉起全量同步任务把生产库三千万行订单灌进数仓。早上业务方打开报表发现昨天物理删除的几百条测试订单还在而新增的订单却少了一批。这不是玄学是 ETL 里最经典的选型翻车现场——全量和增量从来不是“哪个更好”的问题而是“哪个坑你能接受”的问题。这份资料把 ETL 中全量与增量的差异拆成了四个维度数据采集、数据同步、Cube 构建、数据备份。它不讲空泛概念而是直接告诉你全量抽取简单但数据量大、增量抽取精准但对业务库压力敏感全量同步夜里跑、覆盖写但物理删除的数据会变成“看不见的幽灵”增量同步逻辑复杂、时间一长极容易造成生产方和接收方数据不一致。适合正在设计数仓同步链路、调优调度任务、或者被“数据对不上”折磨过的数据工程师。读完你能判断自己的业务该走全量还是增量以及混合策略怎么落地。2. 数据采集与同步全量覆盖和增量追变的选型逻辑2.1 全量抽取的适用边界与物理删除陷阱全量抽取的本质是“不管三七二十一每次把源端所有数据拉过来”。它的优势极其明显实现简单不需要在源库建触发器、不需要解析 binlog、不需要维护位点。一个SELECT * FROM orders加一个写入目标端的逻辑就能跑。但问题也在这里——数据量线性增长今天三千万行明年可能就是三个亿。网络带宽、目标端写入 IO、调度窗口都会被吃掉。更隐蔽的坑是物理删除。假设源端有一条订单被DELETE掉了全量抽取拿到的结果集里自然没有这条记录。如果你采用“新数据全部覆盖旧数据”的方式目标端这条记录会被清掉看起来没问题。但如果你用的是“新旧不一致就更新一致则不更新”的异步写策略这条被删除的记录在目标端永远不会被触发更新它就变成了一个幽灵数据。常见做法是借助源端的操作日志文件比如 MySQL 的 binlog、Oracle 的 redo log或者 CDC 工具把这些“看不到”的变更单独捕获出来再合并到全量结果里。我一般会这样判断如果源表有可靠的updated_at字段且业务允许软删除全量抽取配合时间戳过滤可以覆盖 80% 的场景如果源端存在硬删除且没有日志留存全量抽取必须搭配独立的删除捕获机制否则数据一致性就是一颗定时炸弹。-- 全量抽取的典型写法直接覆盖目标表分区 INSERT OVERWRITE TABLE dwd_orders_full PARTITION (dt ${bizdate}) SELECT order_id, user_id, order_amount, order_status, created_at, updated_at FROM ods_orders WHERE dt ${bizdate}; -- 注意OVERWRITE 会清掉目标分区当天所有数据再写入 -- 如果源端当天有物理删除目标端对应记录也会消失这是符合预期的 -- 但如果目标端还有其他来源写入同一分区OVERWRITE 会误伤这段 SQL 的关键在于INSERT OVERWRITE它保证了目标分区与源端当天快照完全一致。参数${bizdate}是调度系统传入的业务日期通常对应 T-1。需要留意的是如果目标表同时接收多个源系统的数据就不能用 OVERWRITE得改成INSERT INTO配合去重逻辑否则会把其他源的数据冲掉。2.2 增量抽取的位点管理与一致性风险增量抽取只处理“上次抽取之后发生变化的数据”。常见实现方式有三种基于时间戳字段updated_at last_sync_time、基于自增 IDid last_max_id、基于数据库日志binlog/redo log。时间戳方式最简单但要求源端所有变更都会更新updated_at而且时钟不能回拨自增 ID 方式只适合纯插入场景更新和删除捕获不到日志方式最完整但需要额外组件运维成本高。增量抽取最大的风险是“生产方和接收方逻辑不一致”。比如源端一条记录先插入后更新增量抽取只拿到了最终状态但目标端的更新逻辑如果依赖中间状态就会出错。再比如源端批量操作时增量抽取的位点推进和目标端写入不在同一个事务里任务失败重跑时可能重复消费或漏消费。我一般会要求增量任务必须支持幂等写入目标端用MERGE或INSERT ON CONFLICT来保证重复数据不会产生副作用。# 增量抽取的位点管理示例用 Redis 记录上次同步的最大 ID import redis import psycopg2 r redis.Redis(hostredis-host, port6379, db0) last_id int(r.get(etl:orders:last_id) or 0) conn psycopg2.connect(dbnamesource useretl password*** hostsource-host) cur conn.cursor() cur.execute( SELECT id, order_id, user_id, order_amount, updated_at FROM orders WHERE id %s ORDER BY id ASC LIMIT 5000 , (last_id,)) rows cur.fetchall() if rows: max_id rows[-1][0] # 写入目标端使用 ON CONFLICT 保证幂等 for row in rows: target_cur.execute( INSERT INTO dwd_orders (id, order_id, user_id, order_amount, updated_at) VALUES (%s, %s, %s, %s, %s) ON CONFLICT (id) DO UPDATE SET order_amount EXCLUDED.order_amount, updated_at EXCLUDED.updated_at , row) target_conn.commit() # 位点推进必须在目标端写入成功之后 r.set(etl:orders:last_id, max_id)这段代码的核心逻辑是“先写目标端再推位点”。如果反过来位点先推进但目标端写入失败下次任务就会从新位点开始中间那批数据永久丢失。ON CONFLICT DO UPDATE保证了即使同一批数据被重复消费目标端也不会出现重复记录。参数LIMIT 5000是批大小太小会导致频繁提交、吞吐下降太大则单次事务过长、失败重试成本高一般根据单行大小和网络延迟在 1000 到 10000 之间调。2.3 全量与增量在数据同步中的组合策略纯全量同步适合小表或者允许 T1 延迟的维表。比如商品类目表只有几千行每天凌晨全量覆盖一次简单可靠。纯增量同步适合大表且对实时性有要求的场景比如订单表、日志表。但现实中更多是混合策略每天凌晨做一次全量基线白天每隔 15 分钟跑一次增量追变。这样即使增量链路某段时间出问题第二天的全量也能兜底修复。混合策略的关键是“全量基线”和“增量追变”的衔接。常见做法是全量任务先把目标表当天分区覆盖同时记录一个全量完成时间点full_sync_ts增量任务从full_sync_ts开始追变位点初始值就是full_sync_ts。这样全量和增量不会重叠也不会遗漏。需要注意的是全量任务执行期间源端可能还在写入所以全量快照本身可能不是某个精确时间点的一致性视图。如果业务对一致性要求极高全量任务需要配合源端的快照读或者短暂锁表。3. Cube 构建与数据备份全量构建和增量构建的性能账3.1 全量构建与增量构建在 Cube 更新中的差异在 OLAP 场景里Cube 是预聚合的数据立方体。全量构建每次更新时重新计算整个数据集增量构建只对需要更新的时间范围进行计算。这个差异直接决定了计算量和查询性能的走向。全量构建的计算量大但查询时不需要合并不同 Segment。因为所有数据都在一个完整的 Segment 里查询引擎直接扫描即可延迟低且稳定。增量构建计算量小但每次增量都会产生一个新的 Segment查询时需要把多个 Segment 的结果合并。Segment 越多合并开销越大查询性能越差。所以增量构建累计一定量的 Segment 后必须做合并Compaction否则查询会越来越慢。我一般会这样选如果 Cube 的数据量在千万行以内或者业务允许每天凌晨全量重建直接走全量构建省去 Segment 合并的运维成本。如果数据量上亿且只关心最近几天的增量增量构建配合定时合并更划算。参数上合并触发阈值通常设为 10 到 20 个 Segment太小会导致频繁合并影响写入太大则查询性能下降明显。维度全量构建增量构建每次更新计算量整个数据集仅需更新的时间范围查询时 Segment 合并不需要需要Segment 越多开销越大后续 Segment 合并不需要累计一定量后必须合并适用数据量小数据量或全表更新大数据量、按时间分区运维复杂度低高需监控 Segment 数量和合并任务3.2 全量备份、增量备份与差异备份的恢复成本数据备份领域的全量、增量、差异三种方式和 ETL 里的全量增量逻辑相通但恢复路径完全不同。全量备份每次把所有数据写一份备份速度慢、磁盘空间占用大但恢复时只需要拿最近一份全量直接还原恢复速度最快。增量备份只备份上次备份以来的变化量备份速度快、空间占用小但恢复时必须先还原最近一次全量再按顺序重放所有增量备份恢复速度慢且中间任何一个增量损坏都会导致恢复失败。差异备份是折中方案每次备份的是“上次全量备份以来的所有变化”。恢复时只需要最近一次全量加最近一次差异不需要重放多个增量。备份速度、恢复速度、空间占用都介于全量和增量之间。我一般会建议核心业务库每周一次全量、每天一次差异、每小时一次增量。这样最坏情况下恢复时间可控同时磁盘空间不会爆炸。# 全量备份 差异备份 增量备份的调度示例以 PostgreSQL 为例 # 每周日 02:00 全量备份 0 2 * * 0 pg_basebackup -D /backup/full/$(date \%Y\%m\%d) -Ft -z -P # 每天 02:00 差异备份基于最近一次全量 0 2 * * 1-6 pg_dump -Fc -f /backup/diff/$(date \%Y\%m\%d).dump mydb # 每小时增量备份基于 WAL 归档 0 * * * * pg_receivewal -D /backup/wal -P这段脚本里pg_basebackup做全量物理备份pg_dump做逻辑差异备份pg_receivewal持续接收 WAL 日志实现增量。恢复时的顺序是先还原最近一次全量再还原最近一次差异最后重放差异之后的 WAL 日志。参数-Ft表示输出 tar 格式-z启用压缩-P显示进度。注意 WAL 归档目录需要足够的磁盘空间并且要定期清理已经不再需要的 WAL 文件否则磁盘会被撑满。4. 避坑与排查全量增量链路的五个血泪教训4.1 增量任务重跑导致数据重复现象调度任务失败后手动重跑目标表出现大量重复记录主键冲突报错刷屏。 原因增量抽取的位点在任务开始时就已经推进但目标端写入失败后位点没有回滚。重跑时从新位点开始中间那批数据被重复抽取。或者目标端没有做幂等同一批数据写两次就产生两条记录。 解决位点推进必须放在目标端写入成功之后且目标端写入使用MERGE或INSERT ON CONFLICT保证幂等。如果已经产生重复用ROW_NUMBER() OVER (PARTITION BY id ORDER BY updated_at DESC)去重后回写。4.2 全量覆盖误删其他来源数据现象全量任务跑完后目标表当天分区只剩下当前源系统的数据其他源系统写入的记录全部消失。 原因多个源系统写入同一张目标表同一分区全量任务使用了INSERT OVERWRITE把整个分区清空后只写入了自己的数据。 解决如果目标表有多个数据来源全量任务不能用 OVERWRITE应改为INSERT INTO配合DELETE条件删除当前源系统的旧数据再插入新数据。或者按源系统拆分分区各写各的分区。4.3 增量抽取漏掉物理删除现象源端删除了一条记录增量任务跑完后目标端这条记录还在报表数据偏大。 原因增量抽取基于updated_at或自增 ID物理删除不会更新这两个字段所以增量逻辑根本感知不到删除操作。 解决如果业务允许软删除在源端用is_deleted标记代替物理删除增量抽取把is_deleted同步到目标端。如果必须物理删除需要引入 CDC 工具捕获 delete 事件或者在增量任务中定期做全量比对来发现差异。4.4 Cube 增量构建后查询越来越慢现象Cube 采用增量构建刚开始查询很快运行一个月后查询延迟从秒级涨到分钟级。 原因每次增量构建产生一个新 SegmentSegment 数量累积到几百个查询时需要合并所有 Segment 的结果合并开销线性增长。 解决配置自动合并策略当 Segment 数量超过阈值比如 10 个时触发合并任务。合并任务通常在业务低峰期执行合并后查询性能恢复到正常水平。同时监控 Segment 数量设置告警阈值。4.5 备份恢复时增量链断裂现象需要恢复数据库时发现某个时间点的增量备份文件损坏或丢失导致后续所有增量都无法重放。 原因增量备份依赖完整的备份链任何一个环节断裂都会导致恢复失败。而且增量备份文件通常没有校验机制损坏往往在恢复时才发现。 解决定期做恢复演练不要等到真出事才验证备份可用性。差异备份可以作为增量链的兜底每周至少做一次差异备份这样即使增量链断裂最多丢失一天的数据。所有备份文件写入后立即计算校验和恢复前先校验。5. 从全量到增量的平滑迁移一个可复现的验证方法如果你现在的链路是纯全量想迁移到增量为主、全量为辅的混合模式不要一次性切过去。我一般会走一个“双跑验证”的流程新链路增量每日全量兜底和旧链路纯全量同时运行每天比对两边目标表的数据差异。差异为零持续一周后再把读流量切到新链路。具体操作上先在新链路的目标表加一个etl_source字段标记数据来自全量还是增量。然后写一个比对任务每天凌晨全量任务完成后执行-- 双跑验证比对全量链路和增量链路的目标表差异 WITH full_data AS ( SELECT order_id, order_amount, order_status, updated_at FROM dwd_orders_full WHERE dt ${bizdate} ), incr_data AS ( SELECT order_id, order_amount, order_status, updated_at FROM dwd_orders_incr WHERE dt ${bizdate} ) SELECT COALESCE(f.order_id, i.order_id) AS order_id, f.order_amount AS full_amount, i.order_amount AS incr_amount, f.order_status AS full_status, i.order_status AS incr_status, CASE WHEN f.order_id IS NULL THEN 仅增量有 WHEN i.order_id IS NULL THEN 仅全量有 WHEN f.order_amount ! i.order_amount THEN 金额不一致 WHEN f.order_status ! i.order_status THEN 状态不一致 ELSE 一致 END AS diff_type FROM full_data f FULL OUTER JOIN incr_data i ON f.order_id i.order_id WHERE f.order_id IS NULL OR i.order_id IS NULL OR f.order_amount ! i.order_amount OR f.order_status ! i.order_status;这个查询用FULL OUTER JOIN把两边数据全量对齐任何一边缺失或者字段不一致都会被筛出来。diff_type字段直接告诉你差异类型方便快速定位是增量漏抽还是全量覆盖出了问题。参数${bizdate}是业务日期通常跑 T-1 的比对。如果差异行数持续为 0说明增量链路已经稳定可以切流量。如果差异行数忽高忽低重点排查增量任务的位点管理和幂等逻辑。还有一个细节双跑期间目标表的存储成本会翻倍所以验证周期不宜过长一般一到两周足够。验证通过后旧的全量链路不要立刻下线保留一个手动触发的入口万一增量链路出问题可以快速回滚到全量。从那以后我每次做同步链路迁移都强制走一遍双跑验证哪怕业务方催得再急也不跳过。希望帮到你。本文还有配套的精品资源点击获取
返回列表