实时ETL怎么做?四层架构设计与选型实践

作者:谁偷走了我的奶酪2026.11.06 23:00浏览量:0

简介:传统ETL以批处理为主,数据延迟常以天计;实时ETL则将数据从产生到可查询的延迟压缩到秒级。本文拆解实时ETL的四层架构,数据源、采集传输、计算转换与存储服务,梳理CDC、消息队列、流计算等关键组件的选型要点,并给出一致性保障、监控运维等落地建议,帮助读者构建低延迟、高可靠的数据集成链路。

一、先把问题定义清楚:ETL到底在解决什么

ETL是Extract(提取)、Transform(转换)、Load(加载)三个单词的缩写,说白了就是:把数据从一个地方取出来,按规则加工,再写到另一个地方去。概念很简单,但“什么时候取、多久取一次、取出来怎么加工”这三个问题,会把ETL分成两条完全不同的技术路线——批处理与流处理。

很多团队在选型时容易陷入一个误区:听说实时架构更先进,就急着把所有链路都实时化。实际上,选型的第一步不是看哪个工具更流行,而是先回答两个问题:业务对数据时效的真实要求是什么?团队有没有能力承担相应的复杂度?下面展开来说。

二、传统ETL与实时ETL的核心差异

传统ETL是批处理模式:设置定时任务,比如每天凌晨两点执行一次,把前一天的全量或增量数据处理完毕后写入数据仓库。这套模式的优点非常突出:

  • 逻辑简单直观,开发门槛低;
  • 天然可重跑,任务失败后修复代码、重新执行即可,一致性容易保证;
  • 吞吐量可以做到很高,适合大规模历史数据回补、复杂多表关联等重计算场景。

但它有一个致命短板:数据滞后。你早上九点在报表上看到的,是昨天结束时点的业务状态。对于经营分析、月度结算这类场景,T+1完全可以接受;但对于实时风控、实时大屏、系统监控告警、库存动态调拨这类场景,昨天的数据几乎等于没有数据。

实时ETL要解决的正是这个滞后问题:让数据从产生到可查询,延迟控制在秒级甚至毫秒级。它的代价则是架构复杂度、运维成本与一致性保障难度的全面上升。两者的差异可以概括为:

维度 传统批处理ETL 实时ETL
数据延迟 小时级~天级(T+1) 秒级~毫秒级
处理模式 定时批量执行 持续流式处理
架构复杂度 低 高
一致性保障 失败可重跑,容易保证 需幂等与事务设计
开发运维成本 低 高
典型场景 报表、月结、历史回补 风控、监控、实时运营

三、实时ETL全链路架构:自上而下四层拆解

我一直强调,做技术方案之前,先把架构图在脑子里画清楚。实时ETL的全链路从上到下分四层。

3.1 第一层:数据源层——搞清楚数据从哪里来

最常见的数据源包括:业务关系型数据库、应用日志、消息系统、第三方API接口,以及IoT设备上报的传感器数据。

这一层通常不需要改造,但你必须摸清三件事:

  1. 数据形态:结构化、半结构化还是非结构化,决定了下游解析方式;
  2. 变化频率与规模:每天新增多少、峰值写入多大,直接决定下游组件的容量规划;
  3. 源库的日志能力:是否提供完备的事务日志或逻辑复制机制——这决定了后面CDC方案能否落地,以及落地成本。

3.2 第二层:采集与传输层——数据怎么实时出来

数据产生之后,实时传出来有两条主流路径:

路径一:CDC(变更数据捕获)。 原理是监听数据库的事务日志,把每一条增删改操作实时捕获出来,转为结构化事件流。相比在业务库上加触发器、或高频轮询时间戳字段的老办法,日志解析方式对业务系统近乎零侵入:不改一行业务代码,不给业务库带来额外查询压力。选型时要重点确认三点:是否支持全量快照与增量日志的无缝衔接、失败后的断点续传能力、以及表结构变更时的兼容策略。

路径二:日志采集。 应用程序产生的日志文件,通过部署在主机上的轻量级采集器实时传输到下游,适合用户行为埋点、访问日志这类天然以文件形态存在的数据。

采集到的数据,需要用一个高吞吐、可持久化的分布式消息队列来承接。消息队列在这一层承担四个关键职责:

  • 缓冲削峰:上游突发流量先落入队列,下游按自身处理能力平稳消费,避免被冲垮;
  • 上下游解耦:数据源与计算引擎不直接通信,任何一端升级、扩容或故障,都不影响另一端;
  • 可重放:数据在队列中按策略保留一段时间,下游程序出现Bug修复后,可以从历史位点重新消费,这是故障恢复和回溯计算的基础;
  • 分区有序:按业务主键做分区,保证同一条记录的多次变更顺序不乱。

3.3 第三层:计算与转换层——实时ETL的核心

数据从队列流出后,需要完成清洗过滤、格式转换、字段补全、维表打宽、窗口聚合等一系列操作再写出去。这一层技术门槛最高,核心难点在于“状态”二字:

  • 无状态操作:过滤无效记录、字段映射、格式归一化,逻辑简单,故障恢复成本低;
  • 有状态计算:去重、窗口聚合、双流关联、维表补全,需要引擎维护中间状态。这时必须关注状态存储的位置、状态大小的控制、检查点机制的间隔与恢复速度。

一段典型的流式清洗聚合逻辑如下(示意性伪SQL):

  1. -- 示意:流式清洗 + 分钟级窗口聚合
  2. INSERT INTO dws_order_stat_1min -- 分钟级汇总表
  3. SELECT
  4. window_start,
  5. category,
  6. COUNT(DISTINCT user_id) AS uv,
  7. SUM(pay_amount) AS gmv
  8. FROM source_order_events -- 从消息队列接入的原始事件流
  9. WHERE event_type = 'paid'
  10. AND pay_amount > 0 -- 过滤脏数据
  11. GROUP BY
  12. TUMBLE(event_time, INTERVAL '1' MINUTE),
  13. category;

除状态管理外,还有三个必须严肃对待的语义问题:

  1. 端到端一致性:理想目标是“精确一次”,它需要“上游可重放+计算引擎有检查点+下游支持幂等或事务写入”三者配合,缺一环就退化为“至少一次”,只能靠下游幂等兜底;
  2. 乱序与迟到数据:网络抖动、上游重发都会导致事件乱序,应基于事件时间而非处理时间划分窗口,并为迟到数据设计兜底策略;
  3. 维表关联:实时维表如何同步、关联时打宽的是哪个版本,都要明确定义,否则会出现“实时指标与离线指标对不上”的经典问题。

3.4 第四层:存储与服务层——数据写到哪里、给谁用

很多架构图画到计算层就停了,但写入端设计不当,前面所有努力都会打折扣:

  • 按消费场景选存储:面向多维分析的列式OLAP引擎、面向高并发点查的KV或宽表存储、面向检索的搜索引擎、面向报表的数仓分层;
  • 写入语义必须是Upsert:实时链路中同一条记录会被反复变更,目标表必须支持按主键“存在则更新、不存在则插入”,否则会出现重复数据;
  • 分层建设:明细层完整保留变更事实以备追溯,汇总层做分钟级或小时级预聚合以降低查询压力,应用层直接对接看板与在线服务接口。

四、关键组件的选型考量

  1. CDC组件:优先选择基于日志解析的实现,确认对源库类型的支持范围、全量与增量的衔接方式、失败续传能力;
  2. 消息队列:关注吞吐上限、延迟水平、数据保留时长、分区有序性,以及与计算引擎的对接成熟度;
  3. 流计算引擎:SQL化程度(决定上手门槛)、状态管理与检查点能力、精确一次语义的支持程度、文档与人才储备;
  4. 自建与托管的权衡:自建开源组件灵活可控,但部署、容量规划、监控与故障处理的运维负担很重。如果团队人力有限,可以考虑云厂商提供的托管类服务,例如百度智能云上的消息队列、流计算、数据仓库等通用品类,由平台承担部署运维,团队聚焦业务逻辑开发。评估的黄金标准只有一条:总拥有成本与团队能力的匹配度。

五、落地实践:绕不开的六个问题

  1. 一致性与幂等:给每条事件带上版本号或时间戳,写入时只接受更新的版本;或直接依赖目标端主键Upsert兜底;
  2. 延迟监控:在链路各环节埋点上报延迟指标,设置水位告警,别等业务方发现大屏数字不动了才知道链路断了;
  3. 流批双轨校验:实时链路上线初期,保留原有批任务并行运行,每天用批结果校验实时结果,差异率收敛到阈值内再考虑下线批任务;
  4. 故障恢复预案:明确每一位点的续传策略、任务自动拉起机制、极端情况下的回溯重放流程,并提前演练;
  5. 表结构变更:业务表加字段、改类型是常态,链路要预留Schema演进的兼容方案,避免一次DDL变更导致全链路瘫痪;
  6. 从小切口验证:不要一上来就全链路实时化,先选一两个高价值且边界清晰的场景(如实时交易大屏、实时风控信号)试点,跑稳后再横向复制。

六、总结:要不要上实时ETL,怎么判断

实时ETL不是“更高级的ETL”,而是用更高的架构复杂度和运维成本,换取秒级时效的技术决策。给三条结论:

  • 业务能接受T+1,就安心用批处理,简单、稳定、成本低;
  • 存在秒级时效诉求的核心场景,才值得为实时链路投入;
  • 现实中最健康的形态是批流结合:关键链路实时化,其余保持批处理,两侧共用统一的模型与口径定义。

工具会迭代,架构会演进,但“按业务时效要求倒推技术方案”这条选型逻辑不会过时。先把架构图在脑子里画清楚,再动手,远比追着工具清单跑更重要。