CTO 观点:如何为企业选择合适的消息系统?
我是 Big Data Institute 的常务董事,技术评估是我的一项主要工作。我们帮助企业根据业务需求选择并落地最合适的技术。我们不与供应商合作,因此客户尤为看中我们能够客观地评估不同的技术。
在本文中,我将从 CTO 的视角出发,对比 Apache Pulsar 和 Apache Kafka。只进行理论上的对比空洞无效,也不能帮助我们作出决策,实际用例才真正值得参考。所以,在本文中,我会通过一些常见的实际使用场景来对比 Pulsar 和 Kafka,即简单消息使用场景、复杂消息使用场景和高级消息使用场景。在这些实际使用场景下,Pulsar 和 Kafka 的表现能够帮助我们更好地理解二者的性能和优势,进而作出决策。
假设有一个企业,之前从未使用过消息系统,现在需要通过一个简单的消息系统,将消息从位置 A 发送到位置 B,但不需要复制消息。
数据架构师团队在深入研究 Pulsar 和 Kafka 的业务案例后,得出如下结论:在这一使用场景中,Pulsar 和 Kafka 都没有绝对优势。并且,他们认为在短时间内,该使用场景基本不会发生改变。
对于类似这样的简单消息使用场景而言,我也赞同 Pulsar 和 Kafka 都没有绝对优势。仅从技术角度出发,Pulsar 和 Kafka 这一回合打成平局,那么我们只能考虑成本。二者的运营成本、员工培训成本分别是多少?我打算根据 Kafka 或 Pulsar 的服务提供商的收费标准进行对比。对比开销时,选好服务提供商也可以在一定程度上减少运营成本和员工培训成本。Kafka 的云服务提供商,我参考了使用 Kafka API(Azure)的 Confluent Cloud、MSK(AWS)和 Event Hubs。Pulsar 的云服务提供商,我选择 StreamNative Cloud。
出于稳妥考虑,我们决定选择 Kafka API。目前,已有多种技术支持非 Kafka broker 使用 Kafka API 或传输协议。使用 Kafka API,非 Kafka broker 可通过添加新库支持 Kafka 的传输协议,保证对 Kafka API 的兼容性,从而最大化技术选择的多样性。例如,可以通过修改 Kafka API 的实现重新编译或通过 Pulsar broker 解析 Kafka 的协议(KOP),将 Pulsar 用作 Kafka 的后端。
我们在对比单位成本后,选择了成本效益高的一方。Kafka API 可以保证后端质量,用户在后端之间的数据移动不会受到影响,有效规避风险。即使社区不活跃,技术热度不高,我们的使用也不会受到影响。
假设一个公司需要复杂消息系统。由于需要处理世界各地的数据,必须支持跨地域复制。该企业一直在使用消息系统,因此对实时系统的复杂性有一定的了解,也发现了当前消息系统的不足之处。因此该企业对消息系统的要求是能够处理高级的消息传递和复杂的消息特性。
数据架构师团队和股东以及业务部门详细讨论了当前和未来需求。最后得出的结论是,Pulsar 和 Kafka 各有优势。同时,他们认为随着时间的推移,该使用场景和数据量都会有所增长。
在这种情况下,Pulsar 和 Kafka 难分胜负。要想作出正确决策,必须深入研究二者的使用场景。
Kafka 既提供私有的(价格高)跨地域复制,也提供开源的(附加服务)跨地域复制解决方案。私有的跨地域复制解决方案为其内置特性,但价格高昂。开源的解决方案(MirrorMaker)实际上就是数据复制,但由于不是其内置特性,会增加运营开销。
Pulsar 提供开源内置的跨地域复制特性,支持复杂的复制策略。对于使用场景和数据量都在增加的企业而言,显然,支持内置跨地域复制策略的 Pulsar 完胜。
就跨地域复制而言,我们选择 Pulsar。
由于企业正在向新消息平台迁移,消息系统最好可以处理新使用场景。数据架构师团队一直在了解各个平台,尝试寻找最佳解决方案。在当前使用的消息系统中,一旦出现处理错误,必须重新生成消息,再手动重试,因此最好还可以引入消息延迟发送。另外,当前消息系统的 schema 实施功能也有待加强,各个团队选择不同的 schema 实现时,团队合作的难度显著增加。
Kafka 没有内置死信队列特性,一旦消息处理失败,必须手动处理,或修改代码重试。Kafka 也没有延迟发送消息的内置机制,延迟发送消息流程复杂、工作量大。另外,Kafka 没有内置 schema 实施机制,导致云服务提供商分别提供了不同的 schema 解决方案。
Pulsar 内置死信队列特性,当消息处理失败,收到否认 ack 时,Pulsar 可以自动重试,但次数有限。Pulsar 也支持延迟发送消息,可以设定延迟时间。对于 Pulsar 而言,schema 级别高,因此 Pulsar 有内置 schema 注册,Pulsar API 也原生支持 schema。
就复杂消息而言,我们选择 Pulsar。
随着对架构的深入了解,我们发现为了确保均匀分配资源,需要循环发送同一 topic 上的数据,并且需要通过排序确保消息有序排列。
Kafka 不能分发消息给指定的 consumer。当 consumer 接收到不属于它消费的消息时,要保证这些消息被正确消费,我们只能重新发送这些消息到额外的 topic 中,但这样会造成数据冗余,增加使用成本。因此,我们需要可以制定路由规则发送给指定 consumer 的产品。
Pulsar broker 可以通过制定的路由规则,把一个 topic 的不同消息根据路由规则发送到指定的 consumer 中。Pulsar broker 轻松实现了我们的目标,无需任何额外工作。
就高级消息传递而言,我们选择 Pulsar。
为了全面比较 Pulsar 和 Kafka,我们还需要看一下二者的部署数量和社区概况。
从服务市场来看,Kafka 的提供商更多,销售和支持 Kafka 产品的团队也更多。Kafka 和 Pulsar 的开源社区都积极活跃,但 Kafka 的社区规模更大。
从使用市场来看,Kafka 和 Pulsar 都已部署在大公司的大型生产环境中。在生产环境中部署 Kafka 的公司在数量上更胜一筹。
从用户数量来看,Kafka 的用户更多。但是,数据工程师团队认为, Kafka 的使用者可以轻松学习 Pulsar。
就服务支持和社区而言,我们选择 Kafka。但值得一提的是,Pulsar 社区正在迅速发展。
由于 Pulsar 和 Kafka 在这一使用场景中都有明显的优劣势,决策难度大大增加。
Pulsar 可以在社区和部署上奋起直追,Kafka 则可以努力丰富产品特性。
在作出决策前,我们先来总结一下,该企业在技术上最看重哪方面;在技术方面,我们是否需要做最保守的选择。根据以往的经验,新的开源技术会带来更多惊喜,因此我们更倾向于选择 Pulsar。
如果选择 Kafka,我们需要承担向业务赞助商坦诚“我们无法处理这一使用场景”的风险。甚至,即使支付大笔资金购买跨地域复制许可,也无法保证顺利实现客户的需求。业务团队最终可能需要花大量时间(甚至几个月)来编写、完善、测试他们的工作方案。
如果选择 Pulsar,我们可以告诉业务赞助商“一切尽在掌握中”。由于 Pulsar 的各项内置特性都已经过测试,使用团队可以在短时间内完成部署。
在这种情况下,因为我们不需要 Kafka API 的独有特性,所以我们没有使用支持 Kafka 协议(KOP)的 Pulsar Broker,而是选择 Pulsar API,因为 Pulsar API 支持所有我们需要 Kafka API 提供的功能。
决策如下:选择 Pulsar,可以优先处理业务请求,开发团队只专注编写代码,而不是解决其他问题。选择 Pulsar 的同时,也关注 Pulsar 社区和提供商的动态。
如果采取保守决策选择 Kafka,需要接受可能无法实现某些使用场景的事实。对于相似的使用场景,我们采取相应解决方案。调整项目时间规划,增加实行预期解决方案的时间。联系运营团队,确保可以承受执行预期解决方案的开销。
假设一个公司已经在使用多种消息和队列系统。从运营、架构和开销的角度来看,我们认为有必要迁移到单个系统。同时,我们也希望降低运营成本。
数据架构师团队在和股东以及业务部门详细讨论了当前和未来需求后,给出的结论是,Pulsar 和 Kafka 各有优势。
最大的难题是 RabbitMQ 系统。我们使用 RabbitMQ 发送太多消息,RabbitMQ 已经无法满足需求。我们调整了 RabbitMQ 的代码,将消息缓冲在内存中,并继续创建新集群来处理负载。但是我们需要的不是变通方法,而是一个能够处理大规模消息的系统。
数据架构师在研究这一使用场景时,得出结论:新系统必须可以同时处理消息流模型和队列模型。我们不仅需要继续使用 RabbitMQ 处理消息,也需要更高级的消息技术。
Kafka 擅长消息传递,也可以处理大规模消息流,但是无法处理队列。开发团队可以尝试一些解决方案,但这样就不能实现使用单个系统的预期目标。要处理队列使用场景,就同时需要 Kafka 集群和 RabbitMQ 集群。Kafka 集群更像一个缓冲区,可以有效防止 RabbitMQ 集群过载。但是 Kafka 不支持原生 RabbitMQ,我们需要与提供商合作或自己编写代码,才可以实现在 Kafka 和 RabbitMQ 之间移动数据。
Pulsar 可以在同一集群中处理队列和消息,还支持扩展集群。Pulsar 可以将所有消息流模型和队列模型的使用场景整合到一个集群中。用户可以继续使用 RabbitMQ 代码,Pulsar 支持 RabbitMQ 连接器,或者在 broker 中使用 StreamNative 开发的 AoP(AMQP 协议处理插件),该插件已获得 Apache 许可。
如果不想继续使用 RabbitMQ 代码,则可以使用 Pulsar API。Pulsar API 具有和 RabbitMQ 相同的队列功能。用户需要对代码进行相应修改,工作量取决于原代码的结构和细节,修改代码后,还需要对代码进行评估测试。
就队列模型和消息流模型而言,我们选择 Pulsar。
数据架构师分析了数据使用情况,发现 99.99% 的数据在首次使用后就未被读取。但是,他们决定采取保守策略,保留消息一周。虽然决定存储数据一周,但我们不希望增加太多运营成本。分层存储可以保存数据到本地,然后卸载其他数据到 S3,降低长期保存数据的成本。
Kafka 团队正在开发分层存储,但 Kafka 目前还不支持这一特性。一些服务商提供私有分层存储,但我们不确定是否可以直接用于生产环境中。
分层存储是 Pulsar 的原生特性,可以直接用于生产环境。目前已有多个企业在生产环境中部署该特性。
就分层存储而言,我们选择 Pulsar。Kafka 正在全力开发分层存储,这一特性的重要性不言而喻。
由于我们使用多个 topic 来分解数据,我们期待新系统可以创建大量 topic。数据架构师认为,我们起初需要 10 万个 topic,随着时间的推移,这个数字将会涨到 50 万。
Kafka 集群支持创建的分区数量有限且每个 topic 至少需要一个分区。Kafka 正在增加可支持 topic 的数量,但新特性尚未发布。另外,Kafka 没有命名空间和多租户,因此无法基于 topic 对资源进行分片,十万个 topic 需要存储在同一个命名空间中。
一些企业的确在使用 Kafka 集群存储甚至更多的 topic,同时进行了资源分片。但他们放弃使用单一集群,同时还需要为此支付费用。
Pulsar 支持存储数百万个 topic,这一功能早已发布并投入生产环境。Pulsar 支持命名空间和多租户,用户可以为每个 topic 设置资源配额,进而节约开销。
就 topic 而言,我们选择 Pulsar。
由于我们假设该企业曾经使用 RabbitMQ,在设计上,一般通过 broker 路由机制把 topic 上的数据转发到不同的 topic 中。例如,有一个用于存储世界范围数据的 topic,而 RabbitMQ broker 把它处理成以国家为单位的 topic。
数据架构师团队深入研究了如何在消息系统中使用单一 topic 存储世界范围的数据。他们发现当接收数据量增大时,下游 consumer 无法继续处理数据。对每个下游系统进行反序列化、查看数据,再丢弃数据的流程繁杂,且费时费力。
Kafka 将所有数据存储在单一 topic 中,但是,当 consumer 需要过滤的数据量增加或集群过载时,这个方法不可行。我们通常需要进行水平缩放,增加 consumer 数量,才可以读取全局 topic 并做进一步处理。用户只能选择:编写自定义 consumer / producer,编写 Kafka Streams 程序,或使用专有 KSQL。
Pulsar 支持使用 Pulsar Functions 或自定义 consumer / producer 进行路由,因此可以先读取全局 topic,再将数据保存到以国家为单位的特定 topic 上。使用独立 topic,consumer 可以按需订阅 topic,只接收相关消息。
就路由而言,我们选择 Pulsar。
时间是影响最终决策的主要原因。我们是否有时间让 Kafka 赶上 Pulsar?我们是否有时间让数据工程师来实现 Kafka 的解决方案?等待会让公司错失良机,延缓增加新的使用场景,影响业务发展。
最终决策:我们选择 Pulsar。
时间充足情况下的决策:延迟使用新架构。给 Kafka 半年时间,看 Kafka 是否可以在性能上赶超 Pulsar。如果可以,我们将在生产环境中测试这些新特性,评估稳定性。如果 Kafka 不能让人眼前一亮,我们仍然会选择 Pulsar。
本文涉及的三个使用场景都是我在实际工作中遇到的,希望本文给出的解决方案可以为您提供参考,帮助您根据具体使用场景进行技术评估。