Apache Kafka诞生的背后故事

本文探讨了 Apache Kafka 的起源,揭示了它在 2012 年由领英(LinkedIn)创建,旨在解决其严峻的数据集成挑战。这些挑战包括手动的流程维护、数据积压、系统脆弱以及数据结构(模式)演进困难等。Kafka 成功地提供了一个健壮、可扩展、实时且读写解耦的解决方案,但并未原生解决模式管理、数据集成和所有权这三个核心问题。文章强调,模式在数据集成中扮演着至关重要的角色,而 Kafka 缺乏对模式的一流支持是其最大的缺陷,尽管领英在早期就已认识到并解决了这一问题。

领英(LinkedIn)最初面临的困境

在 2012 年左右,领英创建 Kafka 的初衷是为了解决一个数据集成问题。网站的活动数据(如点赞、发帖、浏览等)被用于多种核心功能,包括欺诈检测、职位匹配、模型训练和信息流等。这意味着数据基础设施必须极其稳固。

然而,他们当时的基础设施却并非如此,主要由两个独立的管道组成:

    • 批处理管道:一个每小时运行的批处理系统,用于将数据加载到数据仓库。此过程涉及多个手动步骤,效率低下。
    • 实时监控管道:一个用于监控服务器指标的实时系统。添加新指标的过程非常繁琐,且数据被锁定在单一系统中,无法与其他数据整合分析。

这两个系统都存在共同的痛点:

    • 大量手动工作:维护和添加新数据都需要耗费大量人力。
    • 严重工作积压:中心化团队资源有限,无法满足业务方不断增长的数据需求。
    • 缺乏集成:两个系统是点对点的,数据只能流向单一目的地,系统之间无法互通。

难以扩展的架构问题

随着业务发展,领英意识到整合不同来源的数据能创造巨大价值。但现有的架构使其无法扩展,暴露出了一系列根本性问题:

    • 模式解析困难:系统中有数百个 XML 模式,需要编写自定义代码才能将其映射到下游系统(如 Hadoop),这个过程耗时、易错且计算成本高。
    • 系统脆弱:数据管道是关键链路,任何问题都会直接影响网站的核心功能。不可靠的数据只会产生更差的结果。
    • 模式演进困难:在不破坏下游系统的情况下添加或删除字段非常困难。由于团队间沟通不畅,模式有时会发生意外变更。
    • 数据延迟:无法实时查看活动指标,数据需要数小时才能通过批处理获得,导致问题发现和解决的周期过长。
    • 数据孤岛:运营指标数据与用户活动数据相互隔离,无法关联分析,阻碍了对网站问题的深入理解。

将干净、完整的数据锁在数据仓库里,无法满足整个组织的需求。更不用说它需要数小时的延迟才能到达,这对任何希望更快访问数据的人来说都是一个大问题。

Kafka 的诞生与局限

基于以上痛点,领英的需求变得非常清晰。他们需要一个健壮、可扩展、支持高扇出、实时、易于集成的标准化数据管道。

最终,他们创造了 Apache Kafka,它解决了大部分核心需求:

    • 健壮性:作为分布式系统,内置的复制、故障转移和持久性保证了管道的稳定。
    • 可扩展性:通过分区(Partition)机制,可以在普通硬件上水平扩展。
    • 高读取扇出:日志(Log)数据结构的无锁设计,使得大规模读取变得简单。
    • 实时性:系统以秒为单位处理数据,而非小时。
    • 读写解耦:数据被持久化到磁盘,允许消费者按自己的节奏处理,慢消费者不会影响整个系统。

然而,还有三个关键问题 Kafka 本身并未直接解决:模式(Schema)、数据集成和所有权

模式:被忽视的核心

领英的团队很早就认识到,要实现真正的“即插即用”式数据集成,必须在上下游系统间统一模式。如果模式不一致,就总需要有人编写额外的转换代码。

理想情况下,你可以完全自动化地将数据卸载到接收端,因为除了调用特定系统的 API 外,没有额外的工作要做。

他们的解决方案是:

    • 采用 Avro:从 XML 转向 Apache Avro 作为统一的模式和序列化语言,数据体积显著减小。
    • 建立模式注册中心:开发了一个服务来存储 Kafka 主题(Topic)的模式及其所有历史版本,这正是 Confluent Schema Registry 的前身。
    • 推行“写入时定义模式”(Schema on Write):将数据清洗前移,在数据进入 Kafka 时就确保其拥有干净、规范的格式。这使得干净的数据可以被任何实时或批处理系统直接使用。
    • 转移所有权:将定义和维护数据模式的责任从管道团队转移给数据创建者,因为他们最了解数据的含义。同时,建立强制性的跨团队代码审查流程,确保模式变更不会破坏下游。

对当今 Kafka 的反思

作者对一个现象感到非常困惑:既然领英在十多年前就认识到模式的极端重要性并构建了相应解决方案,为什么模式支持从未成为 Apache Kafka 的核心功能

我相信,缺乏一流的模式支持是 Kafka 最大的错误。

    • 模式是必须的:几乎所有有价值的用例都需要模式。无论是数据集成还是流处理,都无法在无结构的二进制数据上进行。
    • 社区方案碎片化:由于官方缺失,社区出现了数十种模式注册中心方案,缺乏统一标准。
    • 缺乏服务端验证:模式验证仅在生产者客户端进行,无法阻止恶意或有缺陷的客户端写入脏数据,从而无法保证数据的统一性。

作者认为,如果 Kafka 能在服务端强制执行模式,许多高级功能将变得轻而易举,例如:

    • 原生集成数据湖(如 Iceberg)。
    • 语义验证(如校验邮件格式)。
    • 基于策略的字段过滤(如敏感数据访问控制)。
    • 直接在服务端过滤“毒丸消息”,而无需在每个消费者应用中编写复杂的处理逻辑。

事后看来,“无模式”的风潮已经过去。就像 NoSQL 与 SQL 的战争一样,最终胜出的模型证明了结构化数据的价值。Kafka 在诞生之初就解决了模式问题,但这一核心洞见却在后续发展中被遗忘了。