在分布式系统和微服务中,消息代理必不可少。它们支持异步通信、分离服务并增强可靠性和可扩展性。现代架构严重依赖消息代理,使其成为许多设计模式中的关键组件。
Kafka 和 RabbitMQ 是两种最受欢迎的消息代理。它们以可靠、高效和适应性强而闻名,并拥有出色的文档、支持和社区。
RabbitMQ 是一种免费的开源解决方案,根据 Apache License 2.0 和 Mozilla Public License 2 获得双重许可。它允许您根据需要使用和修改它。它充当纯消息代理,支持多种协议并提供附加功能。
Kafka 也是根据 Apache 2.0 许可证开源的,它不仅仅是一个消息代理,而是一个分布式事件流平台。它提供了包括 Kafka Streams 在内的高级功能。
在比较 RabbitMQ 和 Kafka 时,没有“更好”的解决方案;而是要找到最适合您的架构和目标的解决方案。
本文将带您了解主要功能和特性,并直接比较两者。它旨在全面了解 Kafka 和 RabbitMQ 之间的差异,帮助您根据具体问题和要求做出明智的选择。
RabbitMQ 支持各种协议,例如:
另一方面,Kafka 使用针对高吞吐量进行了优化的二进制 TCP 协议,并依赖于“消息集”抽象。此抽象允许网络请求将消息分组在一起,通过发送批量消息而不是单个消息来减少网络往返的开销。Kafka 的自定义协议为高负载场景的开发和优化提供了灵活性。
但是,自定义协议也有缺点。它将 Kafka 与其他消息代理隔离开来,导致缺乏互操作性。与与任何 AMQP 客户端兼容的 RabbitMQ 不同,Kafka 需要使用 Kafka 客户端。尽管如此,由于 Kafka 的受欢迎程度和社区的努力,Kafka 客户端可用于多种编程语言。
RabbitMQ 和 Kafka 中的路由方法有很大不同。
RabbitMQ路由的主要组件:
在深入研究交易所之前,我们应该澄清另外两个概念:
Exchange 有四种类型:
*(星号) 匹配一个单词。
#(hash) 匹配零个或多个单词。
例如,使用路由键“apple.*.banana”绑定的队列将接收带有“apple.orange.banana”或“apple.strawberry.banana”等键的消息。使用#.banana绑定的队列将接收带有“apple.banana”或“apple.orange.banana”等键的消息。
Kafka 的路由比较简单,主要组件有:
与 RabbitMQ 相比,Kafka 的路由功能有限。它不是为精细路由而设计的,而是为高性能和可扩展性而设计的。
这里需要注意一件重要的事情:
在RabbitMQ 中,当消费者从队列收到消息时,他们会“窃取”该消息。如果成功确认,其他消费者将不会收到该消息。如果 Kafka 消费者属于同一个消费者组,则其行为方式相同。消费者组是 Kafka 的一个抽象概念,允许多个消费者独立读取同一个主题,确保每个消费者组处理所有主题消息。
在 RabbitMQ 中,耐用性和持久性是截然不同的特征:
持久性。这是队列和交换器的一个属性。队列有两种类型:持久队列和临时队列。持久队列(或交换器)将其元数据存储在磁盘上,并且可以在代理重新启动后继续存在。临时队列则不然。
持久性。持久队列不保证消息持久性。要使其持久,您必须配置持久性。发布者发送消息时,可以指定持久性属性。在这种情况下,消息将存储在内部磁盘存储中,并在代理重新启动后可用。
Kafka 将所有内容存储在磁盘上。与 RabbitMQ 在消费者确认后删除消息不同,Kafka 会保留所有消息,直到它们达到生存时间 (TTL) 或磁盘大小限制。它允许不同或相同的消费者组重新处理消息。
RabbitMQ 和 Kafka 都支持集群,其中多个代理协同工作。
在 RabbitMQ 中,集群可提高可用性并确保数据安全。如果我们谈论性能,那么垂直扩展是提升 RabbitMQ 的首选方法。水平扩展可能会增加大量同步开销。通常,您更愿意拥有一个 3 个代理的集群,以确保在一个代理发生故障时可用性。
RabbitMQ 不支持开箱即用的队列分区,但值得一提的是,它具有
Kafka 可高效扩展。它不仅提供可用性和数据安全性,而且还提高了数据处理的吞吐量。这里的关键概念是分区。每个主题都有可配置的分区数量。每个分区都独立于其他分区运行,充当物理数据存储和处理。您可以在集群中复制每个分区,从而确保容错能力。生产者和消费者仅使用主(或主要)分区。如果具有此分区的代理发生故障,系统将从副本中选择一个新的主分区。
选择正确的分区数量至关重要。如果节点发生故障,大量的分区会减慢系统恢复速度。相反,它会限制消费者组的吞吐量和并行度。在一个消费者组中,每个分区只能与一个消费者一起工作(这实际上是应用程序中的一个线程)。因此,拥有三个分区是没有意义的,因为其余的消费者将处于空闲状态。
RabbitMQ 保证单个队列内的顺序。一个消费者将按顺序处理消息。但是,如果有多个消费者,情况就会发生变化。如果一个消费者失败,系统会将未确认的消息返回到队列,但下一个消费者可能已经在处理下一批消息。那么,有什么选择呢?
RabbitMQ 和 Kafka 提供“至少一次”传递保证,这意味着可能会出现重复,但消息至少会被完全处理一次。
Kafka 有更多交付特性:
正如前面提到的,Kafka 通过放弃路由灵活性,带来了强大的功能。
Kafka 提供了强大的流处理库:
使用 Kafka Streams,您可以对主题执行时间聚合并将结果推送到另一个主题或数据库。
假设您有一个包含不同货币对汇率的主题,并且您想要汇总时间段内(5 分钟、30 分钟、1 小时等)的开盘-最高-最低-收盘图(也称为 OHLC)数据。
一种选择是将数据存储在时间序列数据库中,这适合进行此类处理。但是,如果您有 Kafka,则不需要这样做。使用简单的 Kafka Stream 聚合,您可以在 Kafka 主题之上计算 OHLC 数据,并将结果放入任何数据库中以供进一步查询。
Kafka 还允许您将处理后的消息表示为表。它将聚合结果放入表抽象中,您可以通过 KSQL 访问该表。这样的表状态是持久的。如果代理重新启动,它将从相应主题恢复最新状态。
如我们所见,Kafka 超越了基本的消息代理功能,进入了实时处理和 ETL 领域。
Kafka 和 RabbitMQ 都是高吞吐量、低延迟场景的绝佳工具。选择取决于用例、架构和未来需求的具体情况。例如,Kafka 是长期交易事件存储的理想选择,而 RabbitMQ 则在需要协议兼容性和路由灵活性的场景中表现出色。当 RabbitMQ 和 Kafka 都适合时,请考虑您的未来需求。