把 Kafka 用成数据库的边界与代价
Kafka 用 log compaction + KTable 可以做"事件数据库",但代价是什么?什么时候该用,什么时候不该用,本文给出一份边界图。
"用 Kafka 当数据库"是流式架构里最容易被滥用的模式。Log compaction 让 Kafka 可以保留每个 key 的最新值,KTable 让消费端可以"查询当前状态"——听起来这就是个数据库。但真做生产业务,会发现它有非常具体的边界。本文把这些边界拆开讲。
什么是"把 Kafka 当数据库"
典型模式是这样的:
- 所有状态变更写到一个 Kafka topic(compacted)。
- 每个变更包含 key + value,key 是实体 ID。
- 消费端启动时从头消费,重建出"当前状态"(KTable)。
- 查询走 KTable,不查外部数据库。
这个模式看起来很美:单系统、事件溯源、天然审计。但它有几个边界。
边界一:查询模式
KTable 只支持按 key 查询。如果你的查询是"查所有余额大于 1000 的账户",Kafka 没法做。需要:
- 另起一个 topic 做索引(按余额排序)。
- 把 KTable 物化到 RocksDB,用 RocksDB 查。
- 或者把数据再同步到 Elasticsearch / Redis。
无论哪种,都已经不是"Kafka 当数据库"了,而是"Kafka + 别的数据库"。
把 Kafka 当数据库的第一个边界:你的查询是不是只有 by-key?如果不是,就需要第二个系统。
边界二:重建成本
KTable 启动时要从头消费 topic 重建状态。topic 有 100 亿条记录时,重建要几小时。这意味着:
- 消费者扩容很慢。
- 故障切换很慢。
- 开发迭代很慢(每次重启都要等)。
Kafka Streams 的 state store 用 RocksDB 做本地存储 + changelog topic,部分解决了这个问题。但代价是每个 consumer 都要本地存一份"状态",磁盘与内存开销线性增长。
边界三:一致性模型
Kafka 是"at-least-once"或"exactly-once"(EOS)。但 EOS 只在 Kafka 内部成立——一旦和外部系统交互,就需要幂等 + 事务。
把 Kafka 当数据库意味着"没有事务跨 Kafka 与外部系统"。比如"写 Kafka + 写 Redis"是没法原子化的,只能用 outbox pattern 模拟。这比想象中复杂。
边界四:成本
Kafka 的存储成本不低。同等数据量,Kafka 比 MySQL 贵 3–5 倍。原因:
- Kafka 默认 3 副本。
- Kafka 不压缩(虽然支持 zstd 但默认未开)。
- Kafka 的存储按 partition 分,小 partition 浪费大。
把 10TB 的"状态数据"放 Kafka,每月成本可能比放 Postgres 高一个量级。
边界五:延迟
Kafka 的查询延迟是"消费延迟"——从消息写入到 KTable 看到的时间。通常 100ms–1s。这对实时业务够用,但对"读你刚写的"场景就不够。比如用户下单后立刻查订单状态,KTable 可能还没消费到。需要 read-your-write 一致性的场景,Kafka 当数据库不合适。
什么时候"用 Kafka 当数据库"是合适的
| 场景 | 是否合适 | 原因 |
|---|---|---|
| 审计日志 | 合适 | 天然事件溯源 |
| 用户画像 | 合适 | by-key 查询、可重建 |
| 订单系统 | 不合适 | 需要事务、复杂查询 |
| 实时计数 | 合适 | 追加写、聚合读 |
| 账户余额 | 不合适 | 需要 read-your-write |
| 配置中心 | 合适 | by-key、变更通知 |
"事件溯源 + 物化视图"才是正解
真正工程化的做法是"事件溯源 + 物化视图":
- Kafka 存事件流(source of truth)。
- 消费端把事件物化到 Postgres / Redis / Elasticsearch。
- 查询走物化视图。
这种模式保留了"事件溯源"的好处(审计、回放),又避开了 Kafka 当数据库的边界。代价是物化视图的同步延迟与一致性维护成本。
几个工程实践
- 用 log compaction 减少冷数据,但别期待它当数据库。
- 用 Kafka Streams 的 state store 做轻量 KTable,但限制规模在 100GB 内。
- 规模超过 100GB 或需要复杂查询,立刻接外部数据库。
- read-your-write 场景永远走外部数据库。
给团队的简短建议
- 把 Kafka 当数据库前,先回答四个问题:查询模式、重建成本、一致性、延迟。
- 有任一不满足,立刻改方案。
- "事件溯源 + 物化视图"是更通用的解。
Kafka 是个好工具,但它不是数据库。把它的边界看清楚,才能用对地方。