专业书籍精读 · Fundamentals of Data Engineering · 第 7 章
Fundamentals of Data Engineering · Ch 7 · Ingestion · Reis & Housley · 2022
公司每天早上的销售报表,数字来自订单系统、支付系统、App 埋点、合作方发来的表格——它们散在几十个地方。这一章讲的是:怎么把数据从这些「别人家」稳稳地搬进自己的数据平台。这一步叫采集。它看起来只是搬运,却是整条数据流水线最容易出事的地方。
我们总说「批处理」和「实时流」是两种东西。可仔细想想:订单一笔一笔在发生,从来没有停过。所谓「每天一批」,只是我们在一条永不停歇的河上,每隔 24 小时拦了一道闸。批和流不是两类数据,而是你决定多久开一次闸。
多数团队的默认做法是:能定时批量搬就批量搬,只有业务真的需要「秒级看到」时才上实时流;能买现成的搬运工具就别自己写。一句诚实的代价:实时流让数据更新鲜,但它要求一直有人盯着、处理迟到和重复,成本和复杂度都明显更高。
采集是把数据从别人家搬进自己家:批和流只是开闸的频率不同;只搬变化、原样先入库、准备好迟到和重复,比追求「实时」更要紧。
想看有界 / 无界数据、推 · 拉 · 轮询三种模式、快照与增量抽取、ETL 与 ELT 之争、流式采集的迟到 · 乱序 · 重复 · 死信队列,以及 Debezium、Airbyte 的实证? → 切到精读版
你以为采集只是「把数据从 A 拷到 B」,其实它是数据生命周期里最脆弱的一环:源头不归你管、会变、会抖、会重发。本章要建立的认知是:所有数据天生是无界的,批处理只是人为划的边界;采集设计的核心不是选一个工具,而是先回答一串问题——数据多大、多频繁、推还是拉、能否重放、迟到和重复怎么办——再在批与流、ETL 与 ELT 之间按真实需求取舍。
Part II「生命周期详解」第三章。上接第 5 章「数据从哪来」与第 6 章「存在哪」,下启第 8 章查询与转换。第 5 章讲源系统本身,本章讲把数据从源系统挪进存储的那段路。现实里对应 CDC 同步、Kafka 接入、Fivetran / Airbyte 这类托管连接器、每晚跑的导数任务。
设想一家电商:订单库 5 亿行,每天约 200 万行新增或修改;App 埋点高峰每秒 5 万条事件;另有十几个 SaaS 系统(CRM、广告平台)只提供 API。分析师要求「早上 9 点前看到昨天的数」,风控则想「几秒内看到异常下单」。不懂采集的典型后果:
作者把采集定义为把数据从一处移到另一处,并区分了「采集」与「集成」:采集是从源到存储的那一段搬运,集成则是把多个来源的数据拼成一个新数据集。
作者给了一串设计前必须回答的问题:采集的数据会被谁用、能否复用?源与目的地是什么、数据量多大、多频繁?格式是什么、下游能否直接用?如果是流,是否需要先在途中转换?其中最根本的一对概念是有界数据(bounded)与无界数据(unbounded):有界数据有明确的起止(如「9 月 1 日的订单」),无界数据则持续不断地产生。书里的立场很鲜明——数据在被人为划出边界之前,都是无界的。业务事件本来就是一条流,「每日一批」只是我们为了方便处理切出来的。
由此,采集频率不是「批 / 流」二选一,而是一条从「每年一次」到「每天」「每小时」「每分钟微批(micro-batch)」再到「近实时」的连续谱。作者提醒,即便数据以流的方式采集进来,下游也常常以批的方式处理(比如每小时训练一次模型)——频率要分别看每一段。
同步 vs 异步采集。同步管道里,源、采集、目的地环环相扣,后段一步失败,前面几小时的工作可能都得从头重跑。异步管道则以事件为单位、经过缓冲(如 Kafka)流动,各段独立失败、独立重试。
序列化与反序列化。源把数据编码成字节、目的地再解开,两端必须对格式和版本达成一致,否则数据「到了也读不了」。
吞吐与可扩展。管道要扛住峰值和积压:下游停机几小时恢复后,积压的数据会像洪水一样涌来。作者建议优先用托管服务,它们大多内置弹性伸缩。
可靠性与持久性。可靠指管道按预期运行、失败能恢复;持久指数据不丢。关键洞察是:很多源数据一旦没采到就永远没了(比如只在内存里停留的事件),所以冗余与自愈的投入要按「丢了会怎样」来衡量,而不是追求零风险。
负载(payload)。要看清数据的种类(表格、图片、文本)、形状、大小、schema 与数据类型,尤其是schema 演化:上游加字段、改类型、改名是常态。对策是自动检测 schema 变化,或用 schema 注册表(schema registry)给每个版本编号、让读写两端按版本解析;更根本的是和上游团队建立沟通。
推 · 拉 · 轮询。推(push)是源主动发出;拉(pull)是采集系统主动去取;轮询(poll)是定期去问「有没有变化」,有才拉。CDC、消息流多是推,定时导数多是拉。
快照 vs 增量抽取。每次全量抄一份(快照)最简单,但贵;只抽取上次以来变化的部分(差量 / 增量)省资源,却要求源能可靠地标出「什么变了」。以开头那张 5 亿行的订单表为例,每天 200 万行变化,增量抽取的数据量只有全量的约 0.4%。
基于文件的导出。源系统自己把数据导成文件,推到对象存储或 SFTP。好处是源方掌控安全与访问,不必开放数据库直连。
ETL vs ELT。ETL 是先抽取(Extract)、在途中转换(Transform)、再加载(Load)进数仓;ELT 是先把原始数据原样加载进数仓或数据湖,再在里面用 SQL 转换。云数仓把存储做便宜、算力做弹性之后,ELT 成为主流:原始数据留底,转换逻辑可以反复改写重跑。作者同时警告两点:一是 ELT 若只做了「EL」而没人做「T」,数据湖会变成沼泽;二是 ETL 并没有死——数据需要先脱敏、先压缩,或目的地不擅长转换时,在途转换仍然合理。
插入、更新与批大小。列式数仓擅长一次写入一大批,最怕逐行插入和频繁小更新——每一条都可能触发重写一个文件。所以采集时要攒批,按目的地的特性决定批大小。数据迁移(如整库从本地搬上云)则建议先用小样本试跑、核对 schema 差异,最难的往往不是搬数据,而是把上下游所有管道接到新系统上。
流采集把问题从「搬多少」换成了「什么时候、以什么顺序、送几次」。书里逐条列了要考虑的事:
本章后半是一份「工具箱」。最重要的几样:
updated_at 字段查「上次以来改过的行」——简单,但只能拿到每行的最新状态,中间的多次修改和删除会被漏掉;持续 CDC 读数据库的变更日志(如 MySQL binlog、PostgreSQL WAL),把每一次增删改变成事件写进流平台,不丢中间态、对源库查询压力也小得多。代价是要有日志读取权限,并管住源库日志的保留。最后,作者强调采集是人的问题:上游软件工程师决定数据长什么样、何时变;把他们拉进来、约定好变更通知,比任何工具都管用。DataOps 方面,要监控管道的运行、延迟与数据量——量突然掉一半往往是上游悄悄坏了——并对数据做质量测试。
表 1 · 批采集 vs 流采集
| 方式 | 适合 | 代价 |
|---|---|---|
| 每日 / 每小时批 | 日报、财务对账、离线训练;绝大多数分析场景 | 新鲜度以小时计;全量快照会给源库压力 |
| 微批(分钟级) | 运营看板、近实时汇总 | 调度更频繁,小文件变多,需定期合并 |
| 流(秒级) | 风控、实时推荐、监控告警 | 要处理迟到、乱序、重复;7×24 值守,成本与复杂度最高 |
表 2 · 抽取方式
| 方式 | 好处 | 代价 |
|---|---|---|
| 全量快照 | 最简单,结果自洽 | 数据量大时慢且贵;反复扫源库 |
| 批式 CDC(按更新时间) | 只取变化,实现简单 | 漏掉中间态与硬删除;依赖源表维护好时间戳 |
| 日志式 CDC | 每次变更都捕获,低延迟,对源库查询压力小 | 需日志权限与额外组件(如 Debezium + Kafka);运维更重 |
表 3 · ETL vs ELT
| 模式 | 何时选 | 代价 |
|---|---|---|
| ETL | 需在入库前脱敏 / 过滤;目的地算力有限;大幅压缩数据量 | 原始数据不留底,转换逻辑改了难以回溯重算 |
| ELT | 云数仓 / 湖仓;转换逻辑常变;需要可重算 | 原始层越堆越多,没人治理就成数据沼泽;数仓算力账单上涨 |
判据:先问下游真正需要多新的数据——作者的态度是,只有当业务价值确实超过成本时才上真正的流式;再问源能否可靠地告诉你「什么变了」;最后问是否要保留原始数据以便重算——要,就倾向 ELT。
面试里「把业务库同步到数仓」这道题,好的答案会这样落地:用日志式 CDC 把 MySQL 的变更写进 Kafka,按主键分区以保证单行有序;消费端按主键做幂等 upsert,批量写入数仓;原始变更事件同时落到对象存储留底,可重放;SaaS 数据交给托管连接器;监控每张表的延迟与日数据量,量异常即告警;schema 变更走注册表并通知下游。每一步都对应本章一个考量。
开源实证
① 采集 = 把数据从源系统搬进存储;它是生命周期里最脆弱的一环,因为源头不归你管。
② 数据天生无界,批只是人为划的边界;频率是从按年到逐条的连续谱,每一段可以不同。
③ 设计前先回答:数据量、频率、同步还是异步、推拉还是轮询、可靠性要求、schema 会怎么变。
④ 能增量就别全量;按时间戳的批式 CDC 漏删除和中间态,日志式 CDC 每次变更都不漏。
⑤ ELT 是云数仓时代的默认,原始数据留底、可重算;但没人做转换和治理就成沼泽,ETL 在脱敏等场景仍合理。
⑥ 流采集要提前准备迟到、乱序、重复、重放、保留期、消息大小与死信队列;「恰好一次」靠至少一次 + 幂等。
⑦ 列式数仓怕逐行小写,采集要攒批;能买托管连接器就别手写对接。
⑧ 监控延迟与数据量,和上游工程师约定变更通知——人的问题比工具更关键。