学习笔记 · 2026-10-09 · 基础
实时数据流水线指南:流式处理、CDC与事件驱动架构
实时数据流水线把变更累积到事件日志(Kafka)中。流处理引擎(Flink、Structured Streaming、Dataflow)持续加工这些数据,CDC则将生产数据库的变更无延迟地同步出去。本文依据官方文档,梳理各组成部分的作用、在AI服务中的用途、引入顺序和检查项。
- 批处理以分钟或小时为单位一次性处理积攒的数据,流处理则对每条到达的记录以秒或毫秒为单位更新结果。
- Kafka这样的事件日志在事件被读取后也不会删除,而是保留下来,从而把生产者与消费者解耦,并允许多个消费者重新读取。
- 基于日志的CDC读取生产数据库的事务日志,在不给源数据库增加负担的情况下,实时同步包括删除在内的所有变更。
- 流处理的核心难题是时间。通过窗口、水位线和触发器来处理迟到或乱序的数据。
- “事件驱动”指的是通知、状态传递、事件溯源、CQRS等不同模式,因此要先确定使用哪种模式。
是什么、为什么需要:批处理与流处理的区别
长期以来,数据流水线(把数据从源头搬到目的地并在途中加工的流程)以批处理方式为主。根据AWS的介绍文章(w5),批处理周期性地一次性处理一段时间内积攒的数据或固定数量的数据。它适合多次扫描全部数据的深度分析,但延迟以分钟、小时乃至天计。流处理接收源源不断的数据,每到达一条记录就逐步更新分析结果,目标延迟为秒级或毫秒级。
这种区别之所以重要,是因为数据的价值往往随时间流逝而下降。AWS文章(w5)举了根据用户当前位置推荐餐厅的例子:位置数据如果不立即使用就失去意义。Kafka官方介绍(w1)也把实时支付处理、车辆和货物追踪、工厂传感器分析、患者状态监测列为事件流的典型用途。
两者并非只能二选一。AWS文章(w5)说明,许多组织采用同时设置实时层和批处理层的混合模型:用流处理即时得出所需结果,同时把同样的数据存入存储,之后再用批处理做深度分析。
批处理与流处理
批处理攒起来一次处理
- 面向全部或成批数据
- 延迟:分钟·小时·天
- 多次扫描全量数据的深度分析
流处理每到达一条就处理
- 面向最近窗口或最新记录
- 延迟:秒·毫秒
- 按窗口逐步更新
공통 同一份数据可以作为流立即使用,也可以存储后再做批量分析
组成部分:事件日志、处理引擎、CDC
实时流水线大致由三部分组成。第一是事件日志。根据Kafka官方介绍(w1),Kafka是一个把写入和读取事件、在所需期限内安全存储事件、在事件发生时即时或事后处理事件这些功能整合在一起的平台。事件由键、值和时间戳组成,累积在主题(topic,类似文件夹的分组)中。与传统消息系统不同,事件被消费后也不会删除,只有超过每个主题设定的保留期限才会被丢弃。主题被划分为多个分区,相同键(例如客户ID)的事件进入同一分区,并按写入顺序被读取。据介绍,生产环境中常见的设置是复制因子为3,即保留三份数据副本。
第二是流处理引擎。Flink文档(w2)把有状态(stateful)且考虑时间(timely)的流处理作为核心概念,提供从最底层的Process Function、DataStream API、以表为中心的Table API到最高层的SQL等多个抽象层次。根据Databricks的文章(w8),Spark的Structured Streaming让批处理中使用的结构化API可以直接用于流处理,几乎不用修改就能把批处理作业改为流处理作业。Google Cloud Dataflow文档(w7)介绍了用Apache Beam SDK处理窗口、水位线和触发器的方式。Kafka本身也有支持聚合、连接和窗口的Kafka Streams API(w1)。
第三是CDC(Change Data Capture,变更数据捕获)。Confluent的文章(w4)把CDC定义为追踪数据源的所有变更并将其反映到目标系统的过程。根据Debezium文档(w3),Debezium是一组用于Kafka Connect的源连接器,利用各数据库自身的功能读取变更并发送到Kafka。Kafka Connect有数百个社区开发的连接器,通常无需自己开发(w1)。
设计原则:如何处理时间与事件
流设计中最先遇到的问题是时间。Dataflow文档(w7)指出,无法保证数据按时间顺序、以可预测的间隔到达。因此要把源源不断的数据划分为窗口(时间区间)来聚合。窗口包括互不重叠的固定区间——滚动窗口,按固定周期开始、彼此重叠的跳跃窗口(适合移动平均),以及按活动中断间隔划分的会话窗口。水位线是认为某个窗口的数据已全部到达的基准线,越过这条线之后到达的数据作为“迟到数据”单独处理。触发器决定何时输出聚合结果,并区分使用事件发生时间(event time)和处理时间(processing time)。
第二条原则是把生产者与消费者解耦。Kafka官方介绍(w1)表示,将两者完全分离、使生产者不必等待消费者,是实现高可扩展性的核心设计。AWS文章(w5)也介绍了生产者、代理(broker)、消费者的三层结构,并补充说消费者可以把加工后的结果再写回代理,生成新的流。
第三是明确“事件驱动”一词的具体含义。Martin Fowler的文章(w6)将其分为四种。事件通知只告知发生了变更,耦合度低,但跨越多个通知的流程在代码中不可见。事件携带状态传递把变更后的数据放进事件中,让接收方维护自己的副本;即使源系统停机也能运行,但副本会增多。事件溯源把所有状态变更记录为事件,可以随时重放以恢复状态,Git的提交历史就是典型例子。CQRS为读和写使用不同的数据结构。Fowler(w6)警告说,把这些模式混为一谈会导致误判失败原因。
在AI服务中的用途
实时特征:推荐或异常检测模型以“刚刚发生的事”作为输入时会更准确。AWS文章(w5)说明,流消费者负责过滤、聚合、模式匹配和机器学习。把点击和订单事件按窗口聚合(例如最近区间的移动平均,w7)并持续写入特征存储,模型服务就能用最新特征进行预测。
RAG索引更新:Confluent文章(w4)把将生产数据库的INSERT、UPDATE、DELETE传播到缓存、搜索索引、数据仓库和数据湖列为CDC的基本用途。RAG使用的向量数据库也是一种搜索索引,因此可以套用同样的结构。通过CDC接收文档表的变更,只对改动过的文档重新分块和嵌入,就不必定期对全部内容重建索引。尤其是基于日志的CDC还能捕获删除(w3),有助于避免已删除的文档仍留在检索结果中。
监控:AWS文章(w5)说明,服务器日志保持时间顺序,因此便于观察随时间的变化以发现异常。把模型请求和响应日志作为事件流出,并按窗口聚合错误率或延迟,就能比批处理报告更快地发现数据漂移或故障征兆。
分步应用方法
首次引入时,建议按以下顺序进行。第一,挑选一个确实需要实时的结果。如果晚几分钟或几小时也无妨,用批处理就足够了(w5)。AWS文章(w5)也提到,企业通常从收集系统日志、计算移动最小值和最大值等简单用途起步,再逐步扩展到更精细的实时处理。
第二,搭建事件日志并设计主题和键。要把顺序重要的单位(客户、车辆ID)设为键,才能保证同一分区内的顺序(w1)。保留期限和复制设置也在此时确定。
第三,用CDC接入生产数据库的变更。Debezium(w3)在连接器首次启动时,如果旧的事务日志已被删除,可以对当前状态做初始快照,在运行期间也可以执行增量快照。设置过滤器,只接收所需的模式(schema)、表和列,并对敏感列做脱敏处理。
第四,选择处理引擎。如果已经在用Spark批处理,先用Structured Streaming把批处理作业做成原型、再改为流处理,路径最短(w8)。如果需要精细处理状态管理和时间,就用Flink的DataStream API和Process Function;如果想以声明式方式快速构建,则用Table API或SQL(w2)。第五,确定窗口、水位线和迟到数据策略,并把结果接入目的地(特征存储、向量数据库、数据仓库)。最后监控延迟和错误。大多数Debezium连接器都可以通过JMX监控(w3)。
实时管道引入步骤
- 1选定一个用途从确实需要实时的结果入手
- 2搭建事件日志主题·键·保留期限·复制
- 3接入 CDC初始快照·过滤·掩码
- 4选择处理引擎Structured Streaming·Flink 等
- 5确定时间策略窗口·水位线·迟到数据
- 6连接目标端·监控特征存储·向量数据库·延迟监控
检查清单
在搭建阶段确认以下几点:需要保证顺序的单位是否已设为事件键(w1);各主题的保留期限是否足以支持重新处理和故障恢复(w1);是否设置了复制,使单个代理停机时数据仍能保留(w1)。还要确认CDC是否基于日志,以及是否能捕获删除和变更前的值(w3, w4)。
在处理阶段,检查是否已确定以事件时间还是处理时间为基准进行聚合(w7);是否有水位线和迟到数据策略;处理引擎的状态在故障后能否一致地恢复(w2)。数据可能格式混杂或部分缺失,因此要检查是否有校验逻辑(w5)。
在运维和安全阶段,检查包含个人信息的列是否在CDC阶段已脱敏或剔除(w3),以及是否在监控连接器和消费者的延迟(w3)。还要确认已回滚事务的变更不会被错误地反映到目的地(w4)。
实时管道检查项
架构
- 需要保证顺序的单位是否已设为键
- 保留期限是否足以支持重新处理
- 是否通过复制应对 Broker 故障
- CDC 是否能捕获删除和旧值
处理
- 是否确定以事件时间还是处理时间为准
- 是否有水位线和迟到数据策略
- 故障后状态能否一致地恢复
- 是否检查格式错误和缺失
运维·安全
- 是否对敏感列做掩码
- 是否监控连接器和消费者延迟
- 是否过滤已回滚的变更
常见错误与局限
第一,把事件当作命令来用。Fowler(w6)把这种做法称为“被动攻击式命令”:发送方期望接收方执行某个特定操作,却把消息包装成事件。如果把事件通知串成多个环节,整体流程就不会体现在任何一段代码里,只有观察运行中的系统才能弄清楚。
第二,把不同模式混为一谈。Fowler(w6)指出,有些项目声称“事件溯源是一场灾难”,实际问题可能出在 CQRS 或过度的异步通信上。他还写道,CQRS 把读模型和写模型分开,因此会变得更复杂,相当多的同事对它持谨慎态度。事件溯源难以重放与外部系统交织的事件,还必须处理事件模式随时间变化的问题。
第三,选错 CDC 方式。根据 Confluent 的文章(w4),时间戳列方式简单,但捕获不到真正的 DELETE,而且需要修改源表结构。触发器方式能捕获所有变更,但每次写入都会产生额外写入,拖慢源数据库的性能。基于日志的方式对源库负担小,但事务日志格式因厂商而异,后续版本中也可能改变。此外还需要过滤掉已回滚的变更。
第四,事后才考虑扩展。Dataflow 文档(w7)说明,不使用 Streaming Engine 的流式作业无法扩展到超过最初指定的最大工作器数量。每种处理引擎都有这类运维限制,因此在引入之前应先查阅文档。
延伸学习
如果是初学者,先读 Kafka 官方介绍(w1)。其中简要整理了事件、主题、分区、复制等概念,是理解后续文章的基础。接着在 AWS 的说明文章(w5)中查看批处理与流处理的对比表,以及生产者、Broker、消费者的结构。
如果计划接入生产数据库,可以通过 Confluent 的 CDC 文章(w4)比较三种 CDC 方式的优缺点,再通过 Debezium 功能文档(w3)了解快照、过滤、掩码等选项。时间处理方面,Dataflow 文档(w7)对窗口、水位线、触发器的说明配有图示,易于理解。
选择处理引擎时,可以对照阅读 Flink 概念文档(w2)和 Databricks 的 Structured Streaming 介绍(w8)。进入系统设计阶段后,可以借助 Martin Fowler 的文章(w6)厘清团队所说的“事件驱动”属于四种模式中的哪一种。
相关术语
参考资料
延伸阅读(官方文档与技术博客)
- Introduction | Apache Kafka (kafka.apache.org)
- Overview | Apache Flink (nightlies.apache.org)
- Debezium Features :: Debezium Documentation (debezium.io)
- What Is Change Data Capture (CDC)? | Confluent (confluent.io)
- What Is Streaming Data? - Streaming Data Explained - AWS (aws.amazon.com)
- What do you mean by “Event-Driven”? (martinfowler.com)
- Streaming pipelines | Cloud Dataflow | Google Cloud Documentation (cloud.google.com)
- What is Structured Streaming? | Databricks (databricks.com)
视频与课程
视频未被用作正文的依据,仅供想进一步学习的读者参考。
由 AI 根据所列参考资料撰写并经过审核。详情请查看原始资料。


