09 · 工程定位:Kafka 在真实系统中的角色与取舍
目标:理解 Kafka 适合什么、不适合什么,以及它在真实系统架构中的位置
一、Kafka 的本质定位
高吞吐、持久化、可重放的异步数据管道。
所有设计都围绕这个定位展开:append-only log 保证高吞吐和可重放,partition 保证水平扩展,Consumer Group 保证并行消费,offset 由消费者自己管理保证解耦。
二、典型使用场景
| 场景 | Kafka 的角色 | 为什么适合 |
|---|---|---|
| 数据管道 / ETL | 连接数据源和目的地,解耦上下游 | 高吞吐、持久化、上下游独立演进 |
| 事件流处理 | 实时处理用户行为、交易、日志等事件流 | 有序、可重放、支持多消费者 |
| 日志聚合 | 多台服务器的日志集中收集 | 高吞吐写入、持久化存储、可回溯 |
| 事件溯源 | 用不可变日志记录所有状态变更 | append-only 天然契合事件溯源模型 |
三、Kafka 不适合什么
1. 任务队列
传统任务队列(如 RabbitMQ)的工作方式:
- 消费者取一条消息 → 处理 → ack → broker 删除该消息
- 处理失败可以 nack,broker 自动把消息重新投递给其他消费者
- 支持”把任务分发给多个 worker,失败自动重试给别人”
Kafka 做不到这些:
- 消费后不删除消息,broker 不追踪单条消息的消费状态
- 没有单条消息级别的 ack/nack 机制
- 没有”这条失败了请重新分配给别人”的内置能力
- Consumer 按 offset 顺序读取,粒度是 partition 级别而不是消息级别
2. 请求-响应模式
请求-响应需要低延迟的点对点通信:A 发请求,B 快速回应给 A。
Kafka 是异步解耦的:
- Producer 写完就走,不等回复
- Consumer 什么时候读、读多快,Producer 完全不知道
- 没有”把响应路由回原始请求者”的内置机制
- 虽然可以用 correlation ID + 回复 topic 模拟,但比直接 HTTP/gRPC 复杂得多,延迟也高得多
四、并行消费与顺序保证
Kafka 只保证 单个 partition 内消息有序,跨 partition 没有顺序保证。
并行消费意味着多个消费者同时从不同 partition 读取,哪个先处理完是不确定的。这就是 key 路由的核心价值:
- 有因果关系的消息:用相同 key 路由到同一个 partition,在 partition 内保序
- 无关消息:分散到不同 partition,并行处理提高吞吐
这是 Kafka 在吞吐量和顺序保证之间的根本取舍:想要更高吞吐就增加 partition 数量和消费者数量,但跨 partition 的全局顺序就无法保证。
五、关键工程取舍总结
| 取舍维度 | Kafka 的选择 | 代价 |
|---|---|---|
| 吞吐 vs 延迟 | 批量发送、批量压缩换高吞吐 | 引入少量延迟(linger.ms) |
| 可靠性 vs 可用性 | acks=all + min.insync.replicas 保数据不丢 | 副本不足时拒绝写入 |
| 顺序 vs 并行 | 单 partition 内有序,跨 partition 无序 | 全局有序需要单 partition,牺牲并行度 |
| 解耦 vs 实时 | 异步解耦,消费者自主控制进度 | 不适合低延迟请求-响应 |
| 简单性 vs 灵活性 | offset 由消费者管理 | 不支持单条消息级别的 ack/nack |
| 存储效率 vs 随机访问 | 顺序写入 + Page Cache + 零拷贝 | 不支持高效随机读写 |
参考材料
- Kafka 设计文档 — Use Cases:https://kafka.apache.org/42/getting-started/use-cases/
- Kafka 设计文档 — Design:https://kafka.apache.org/42/design/design/
