从零开始重建Kafka,会是什么样?

“如果可以从零开始重新设计 Kafka,一个真正云原生的事件日志系统,它应该具备怎样的特性?”你是否有想过这个问题。本文作者 Gunnar Morling 结合多年来在事件驱动应用、实时 ETL 和变更数据捕获(CDC)领域使用 Kafka 的实践经验,梳理了一份理想版 Kafka.next 的特性清单,看看这个是你想要的吗?

原文链接:https://www.morling.dev/blog/what-if-we-could-rebuild-kafka-from-scratch/

作者 | Gunnar Morling

责编 |苏宓

出品 | CSDN(ID:CSDNnews)

以下为译文:

这几天,我花时间仔细研究了最近公布的 KIP-1150(也叫“Diskless Kafka”,无盘 Kafka),还有 AutoMQ 发布的 Kafka 分支版本。这些新版本把 Apache Kafka 和对象存储(比如 Amazon 的 S3)做了很深度的结合。简单说,就是想让 Kafka 在云环境中用起来更轻松,这些项目效仿了 WarpStream 提出的思路,主要目标是让 Kafka 能根据需求更灵活地扩展或缩减资源(即弹性)、大幅降低使用成本,以及进一步为未来和“数据湖仓一体”(lakehouse)这样的新型数据架构无缝整合打基础。

这些探索让我开始思考:如果今天从零开始,重新设计一个真正面向云原生的、高可靠的事件日志系统(可以叫它 Kafka.next),那它应该具备哪些理想特性呢?

当然,计算和存储分离支持对象存储这些是最基本的要求,但除此之外,还应该具备什么?

结合我这些年用 Kafka 构建事件驱动应用、做实时 ETL(实时抽取-转换-加载数据流程)和变更数据捕获(CDC,Change Data Capture)管道的经验,下面是我个人希望能有的一些功能清单:

  • 取消分区的概念

以前 Kafka 需要把数据分成很多“分区”,这样才能把数据分散到各个服务器本地磁盘上,解决扩展性问题。但在云端,用上了像 S3 这样的超大对象存储后,就不再需要这种分区机制了。

虽然分区还能帮我们保证数据的“顺序性”,但实际上从应用角度来看,这种顺序性没那么有用。一般来说,要么你希望整个主题(topic)里所有消息有全局顺序,要么更常见的是同一个 key 的消息保持顺序

而分区导致的情况是,一些本来无关的消息,仅仅因为哈希碰巧算到同一个分区,就强行有了顺序——这并没有多大意义。所以,新系统里完全可以不再把“分区”暴露给用户。

  • 以 Key 为中心的数据访问方式

与其像现在这样按分区读数据,我们更希望能直接、快速地访问所有属于同一个 key 的消息

也就是说,不用粗略地扫整个主题或分区,而是有几百万条以实体为单位的小流(stream),每条小流对应一个 key。

这样做有很多好处,包括只读取你真正需要的数据,效率更高;消费者(消费者就是读取消息的程序)数量可以根据实际需要动态调整,不再受限于预先固定的分区数;保证了同一个 key 的消息顺序,非常适合做事件溯源(Event Sourcing)架构、基于 actor 或 agent 的系统;还能自然解决传统分区里“堵头”(head-of-line blocking)的问题。如果某条消息处理失败,只影响它自己对应的 key,不会影响其他 key 的消息。

简单说,就是每个 key 成了一个独立的小系统,坏了也只影响自己,而不是连累一大片。

  • 支持 Topic 层级结构

在像 Solace 这样的系统里,可以把消息内容的一部分提升成一个有层次的路径式主题名字(就像文件夹路径一样),比如 orders/usa/california。这样,客户端就可以根据模式(pattern)灵活订阅自己想要的一部分消息,比如只订阅美国加州的订单流。而且服务器(broker)不需要解析完整消息,只需要看路径就能决定怎么分发,非常高效。

  • 并发控制机制

现在用 Kafka 做“最终数据存储”的话有个问题:没办法防止写入的数据是基于旧版本信息的。举个例子:你看到账户余额是 100,想扣 10,但别人刚好在你之前扣了 90,这时你如果直接写,会把余额弄错。

如果有类似乐观锁(optimistic locking)的机制,比如基于 key 版本号的检查,就能避免这种冲突。这样,当一条消息成功提交时,可以保证它看到的是 key 的最新状态,从而避免数据更新丢失。

  • Broker 端原生支持 Schema

现在 Kafka 把消息当成黑盒(二进制数组),完全不管里面是什么内容。这就导致:消费者(读取方)要自己通过旁路机制(比如 Schema Registry)去搞清楚数据格式;如果有坏心眼的生产者(发送方)发了不符合格式的数据,Kafka 也拦不住;也因此,Kafka 的数据很难直接写入像 Apache Iceberg 这种开源数据表格式。

如果 Kafka 能直接在服务器端支持 Schema,就能大大改善使用体验,比如Kafka 本身就能提供标准的接口(比如 AsyncAPI)来描述消息结构;还能直接支持按列(columnar)存储,为不同需求优化数据。

  • 系统扩展性和可插拔性

很多成功的开源项目,比如 Postgres 和 Kubernetes,都有一个共同点:很容易扩展和定制。用户可以通过标准接口添加自己的插件(而不是改核心代码),实现自己的功能。

在 Kafka.next 中,这种可扩展性应该成为基础设计,比如可以写自定义的消息过滤器、消息转换器;支持不同的存储格式(比如按列存储);可以通过插件添加限流、加密、或者让 topic 直接和 Iceberg 表对接的能力。

简单说,就是系统自己尽量少管死,留出空间让用户按需扩展

  • 同步提交回调

现在 Kafka 保证的是“最终一致性”,也就是说,生产者发完一条消息后,并不知道什么时候下游系统(比如数据库)真正处理完了。有些场景下,我们希望当生产者收到确认时,就能确定下游已经同步好了

如果能实现这种同步机制,Kafka 就能真正像一个有强一致性特性的数据库来用了,比如可以实现“写后立刻读到”的体验。

  • 快照功能(Snapshotting)

目前 Kafka 支持“压缩”(compaction)功能,也就是保留同一个 key 的最后一条记录。如果每条记录都包含了完整状态,比如一条订单记录就包含了所有订单信息,那这样压缩是没问题的。但如果是部分更新,比如“订单状态从待支付改成已支付”,那就需要把所有变化都按顺序应用一遍,才能恢复完整状态。

随着变化越来越多,恢复速度就会变得越来越慢。

如果 Kafka 支持内置的快照功能,就能在需要的时候把一系列变化总结成一个当前状态的快照,后续更新基于这个快照继续处理,旧记录可以清理掉,大大提高效率。

  • 多租户支持(Multi-tenancy)

任何现代数据系统,从设计一开始就应该考虑多租户场景。比如,为每个客户快速创建隔离的环境,操作应该既便宜又迅速。同时,不同客户之间在访问权限、安全性、资源使用、计费等方面应该完全隔离,互不影响。

其实,这里提到的一些功能,有些系统已经实现了。例如,S2 支持了超大量小流(high cardinality streams)、Waltz 里有乐观锁(optimistic locking)、Apache Pulsar 做得很好的就是多租户(multi-tenancy)

但,要把这些特点全部集成在一个系统里——尤其是开源系统,目前我还没见过。

回过头来说,以上这些,只是我个人心目中理想版 Kafka.next 应该具备的能力。(当然,强调一下,这篇文章完全代表我个人观点,和我供职的公司 Confluent 没有官方关系。)这些想法,主要是基于我这些年看到大家用 Kafka 想做的各种应用场景和需求总结出来的。不过我相信,每个用过 Kafka 或类似平台的人,心里应该也都有自己的一份清单。

最后,当然有个很重要的问题是:那这样一个系统到底应该怎么设计呢?

关于这个,我今天就先不展开了。不过可以先透露一点:如果要真的实现上面这些功能,基于日志结构合并树(Log-Structured Merge Tree,简称 LSM Tree) 的设计,很可能是个不错的选择。

推荐阅读:

微软被指“抄袭”个人千星项目,开发者控诉:代码大段照搬,我只在README里被说了声谢谢!

“血亏!我花3000+元用Claude做游戏,结果还不如去「白嫖」Gemini 2.5……”

仅改30行Linux代码,立马省电30%?滑铁卢大学团队“神补丁”,已被Linux 6.13并入!

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CSDN资讯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值