Kafka 不仅是消息队列,更是分布式流处理平台。本文讲解 Kafka 的核心流处理能力(Kafka Streams)、事件驱动架构的落地模式,以及 CDC(变更数据捕获) 与事件溯源,帮助你从"用 Kafka 传消息"进阶到"用 Kafka 做流式处理与事件驱动"。
基础概念、分区、副本、顺序消费见「Kafka 分区副本与顺序消费」。
Kafka 的设计源于 LinkedIn 的日志处理需求,本质是一个高吞吐、可持久化、可回溯的分布式日志。它有两个核心能力:
关键特性(区别于普通 MQ):
Kafka Streams 是 Kafka 官方的轻量流处理库,无需独立集群,可作为普通 Java 应用运行,利用 Kafka 做存储与容错。
// 构建流处理拓扑
StreamsBuilder builder = new StreamsBuilder();
// 从 topic "text-lines" 读取记录流
KStream<String, String> textLines = builder.stream("text-lines");
// 1. flatMapValues: 按空格拆分单词
// 2. groupBy: 按单词分组
// 3. count: 统计每个单词出现次数
KTable<String, Long> wordCounts = textLines
.flatMapValues(line -> Arrays.asList(line.toLowerCase().split("\\W+")))
.groupBy((key, word) -> word)
.count();
// 输出到 topic "word-count"
wordCounts.toStream().to("word-count", Produced.with(Serdes.String(), Serdes.Long()));
// 创建 KafkaStreams 并启动
KafkaStreams streams = new KafkaStreams(builder.build(), streamConfig);
streams.start();运行方式:这是一个普通 Java 应用,配置 bootstrap.servers、application.id(用于容错和状态存储),即可本地运行,无需 Kafka Streams 集群。
容错与状态:Kafka Streams 通过**状态存储(State Store)**保存中间状态,状态默认存 RocksDB 并同步到 Kafka 内部 topic(*-changelog),节点故障时自动恢复,实现了有状态流处理的容错。
KTable<Windowed<String>, Long> windowedCounts = textLines
.flatMapValues(line -> Arrays.asList(line.split("\\W+")))
.groupBy((k, w) -> w)
.windowedBy(TimeWindows.of(Duration.ofMinutes(5))) // 5分钟窗口
.count();传统请求/响应架构(同步调用):服务 A 直接调用服务 B,强耦合、易阻塞。
事件驱动架构:服务之间通过事件(Event)解耦——生产者发布事件到 Kafka,消费者异步订阅处理,两者互不感知。
同步调用: A ----请求----> B(A 等待 B 响应,强耦合)
事件驱动: A --发布事件--> Kafka --订阅--> B(A 立即返回,B 异步处理)| 模式 | 说明 | 适用 |
|---|---|---|
| 事件通知 | 发事件通知,不传完整数据 | 通知、触发下游 |
| 事件携带状态传递(Event Carrying State Transfer) | 事件携带完整数据,消费端无需回查 | 解耦查询 |
| 事件溯源(Event Sourcing) | 以事件序列作为事实来源,状态可由事件重放得出 | 审计、可回溯系统 |
| CQRS(命令查询职责分离) | 写模型 + 读模型分离,事件驱动读模型更新 | 高并发读写分离 |
核心思想:不保存"当前状态",而是保存产生状态的所有事件。当前状态 = 所有事件重放的结果。
订单状态 = 由以下事件重放得出:
OrderCreated(2026-08-01) -> OrderPaid(2026-08-02) -> OrderShipped(2026-08-03)
查询当前状态: 依次重放这3个事件 -> 得到"已发货"状态优点:
缺点:
CDC(Change Data Capture,变更数据捕获):捕获数据库的数据变更(插入/更新/删除),以事件形式发布到 Kafka,供下游消费。
| 方式 | 说明 | 代表 |
|---|---|---|
| 基于 binlog | 监听 MySQL binlog,解析变更 | Debezium、Canal、Maxwell |
| 基于查询轮询 | 定时查询变化字段 | 简单但滞后 |
| 基于触发器 | 数据库触发器写变更表 | 侵入数据库 |
Debezium 监听 MySQL binlog,把每行变更转成事件发布到 Kafka topic:
MySQL: UPDATE user SET name='Tom' WHERE id=1
||
Debezium 捕获 binlog
||
Kafka topic "user_change": {op:"u", before:{id:1,name:"Old"}, after:{id:1,name:"Tom"}}CDC 的典型用途:
KStream/KTable、分组聚合、窗口计算,可做实时流处理。| 组件 | 旧版(本文编写时) | 当前 |
|---|---|---|
| RabbitMQ | 3.8/3.9 | 3.13/4.x(quorum queue 为默认推荐) |
| Kafka | 2.x/3.0 | 3.7+/4.x(KRaft 模式取代 ZooKeeper) |
| RocketMQ | 4.x | 5.x(gRPC 通信、简化运维) |
| Java 版本 | JDK 8 | JDK 17+(Kafka 3.7+ 客户端要求) |
本文讲解的消息可靠性设计(投递确认、死信、幂等、顺序)原理不变;注意各中间件版本升级后的配置差异,如 Kafka 的 KRaft 模式、RabbitMQ 的 quorum queue。