原文地址
摘要
作为一个处理过大量微服务架构的软件架构师,经常遇到这样一个反复出现的问题:“我应该使用RabbitMQ还是Kafka?”由于某些原因,许多开发人员认为这两技术是可互换的。虽然这在某些情况下是正确的,但它们之间还是存在各种潜在的差异的。
因此,不同的场景需要不同的解决方案,如果选择错误的解决方案可能会严重影响您的设计、开发和维护软件解决方案的能力。
本文的目标首先介绍基本的异步消息传递模式。然后,继续展示RabbitMQ和Kafka以及它们的内部结构。第2部分分析了这两平台之间的关键区别、它们的各种优缺点以及如何在两者之间进行选择。
异步消息模式
异步消息是一种消息传递解决方案,其中生产者生产消息与消费者消费消息分离。在处理消息系统时,我们通常确定两种主要的消息传递模式——消息队列和发布/订阅。
消息队列
在消息队列通信模式中,队列可以将生产者与消费者解耦。多个生产者可以向同一个队列发送消息;然而,当消费者处理消息时,消息被锁定或从队列中删除,不再可用。只有一个消费者消费特定的消息。
消息队列
顺便说一下,如果消费者未能处理某个消息,消息传递平台通常会将消息返回到队列,其他消费者可以处理该消息。除了暂时的解耦之外,队列还允许我们独立地扩展生产者和消费者,并为处理错误提供一定程度的容错。
发布/订阅
在发布/订阅通信模式中,多个订阅者可以同时接收和处理单个消息。
例如,该模式允许发布者将系统中发生的事情通知所有订阅者。许多消息队列平台经常将发布/订阅与topic主题联系在一起。在RabbitMQ中,topic是发布/订阅的一种特定实现类型(确切地说,是一种交换类型),但在本文中,我将主题作为发布/订阅来整体表示。
一般来说,订阅有两种类型:
1、临时订阅,在这种订阅中,只有当消费者处于运行状态时,订阅才处于活动状态。一旦消费者停止运行,它们的订阅和尚未处理的消息将丢失。
2、持久订阅,只要订阅没有显式删除,它就会被维护。当消费者停止时,消息传递平台维护订阅,可以稍后恢复消息处理。
RabbitMQ
RabbitMQ是一个消息代理的实现——通常被称为服务总线。它本身支持上述两种消息传递模式。其他流行的消息代理实现包括ActiveMQ、ZeroMQ、Azure Service Bus、和Amazon simple Queue Service(SOS)。所有这些实现都有很多共同点;本文中描述的许多概念适用于其中的大多数。
队列
RabbitMQ支持传统的开箱即用的消息队列。开发人员定义命名队列,然后发布者可以将消息发送到该命名队列。反过来,消费者使用同一个队列来检索消息并处理它们。
Message exchanges
RabbitMQ通过消息交换实现发布/订阅。发布者将其消息发布到Message exchanges,而不知道这些消息的订阅者是谁。
希望订阅exchange的消费者,就创建一个队列;然后message exchange将生成的消息插入队列供消费者消费。它还可以根据各种路由规则为订阅者过滤某些消息。
RabbitMQ 消息交换
值得注意的是,RabbitMQ同时支持短暂订阅和持久订阅。用户可以通过RabbitMQ的API来决定他们想要使用的订阅类型。
由于RabbitMQ的架构,我们还可以创建一种混合的方法——一些订阅者组成消费者组,消费者以竞争的方式,共同处理消息。通过这种方式,我们实现了发布/订阅模式,同时还允许一些订阅者进行扩展以处理接收到的消息。
发布/订阅和队列结合
Apache Kafka
Apache Kafka不是以消息代理方式实现。相反,它是一个分布式流媒体平台。
与基于队列和交换的RabbitMQ不同,Kafka的存储层是使用分区事务日志实现的。Kafka还提供了一个Streams API来实时处理流,以及一个Connectors API来方便地与各种数据源集成;然而,这些超出了本文的范围。
云供应商为Kafka的存储层提供了可替换的解决方案。这些解决方案包括Azure Event Hub,在某种程度上还包括AWS Kinesis数据流。还有一些特定于云的和开源的Kafka流处理能力的替代品,但是,再次强调,这些都超出了本文的范围。
topic主题
Kafka没有实现队列的概念。相反,Kafka用主题来分类存储数据。对于每个主题,Kafka维护一个消息的分区日志。每个分区都是一个有序的、不可变的记录序列,不断地添加消息。
Kafka在消息到达时将消息附加到这些分区。默认情况下,它使用一个轮循分区程序在各个分区中均匀地分发消息。
生产者可以修改此行为来创建逻辑消息流。例如,在多租户应用程序中,我们可能希望根据每个消息的租户ID创建逻辑消息流。在物联网场景中,我们可能希望将每个生产者的身份映射到特定的分区。确保来自同一个逻辑流的所有消息映射到同一个分区,可以确保它们按照消费者的顺序传递。
kafka生产者
消费者通过维护这些分区的偏移量(或索引)并按顺序读取它们来消费消息。一个消费者可以消费多个主题,消费者可以扩展可用分区的数量。
因此,在创建主题时,应该仔细考虑关于该主题的消息传递的预期吞吐量。共同消费一个主题的一组消费者称为消费组。Kafka的API通常用来处理消费者组中消费者之间分区处理的均衡,以及存储消费者当前分区偏移。
kafka消费者
kafka实现消息传递模式
生产者可以将消息发送到特定的主题,多个消费者组可以消费相同的消息。每个消费组都可以单独扩展来处理负载。由于消费者维护他们的分区偏移量,所以他们可以选择持久订阅,在重新启动时维护其偏移量,或者临时订阅,通过丢弃偏移量,在每次启动时从每个分区中的最新记录重新开始。
然而,它和消息队列模式还不是很完美的适配。当然,我们可以配置只有一个消费者组的主题来模拟经典的消息队列。然而,这有很多缺点,本文的第2部分将详细讨论。
需要注意的是,Kafka在分区中保留消息的时间不超过预先配置的时间,而不管消费者是否消费了这些消息。这种留存率意味着消费者可以自由地重新阅读过去的信息。此外,开发人员还可以使用Kafka的存储层来实现事件源和审计日志等机制。
结束语
虽然RabbitMQ和Kafka有时候是可以互换的,但是它们的实现是非常不同的。因此,我们不能将它们视为同一类别的工具;一个是消息代理,另一个是分布式流平台。
作为解决方案架构师,我们应该认识到这些差异,并积极考虑在给定的场景中应该使用哪种类型的解决方案。第2部分阐述这些差异,并提供了何时使用它们的指导。
网友评论