人们经常问我。
有个 xx 要求,我应该用 Kafka 还是 RabbitMQ ?
这个问题很常见而且许多人对两者的选择也没有很好的把握。
所以我决定写一篇文章来详细说明:Kafka 和 RabbitMQ 区别,什么场景适合#xff1f;
同时,面试中经常会问到这个问题。
下面我会通过的 6 场景,对比分析一下 Kafka 和 RabbitMQ 的优劣。
一、消息顺序。
有这样的需求:当订单状态发生变化时,向所有关心订单变化的系统发送订单状态变化的信息。
订单将创建成功、待付款、已付款、已发货的状态,这种状态是单向流动的。

。
好,现在我们将订单状态变化的消息发送给所有关心订单状态的系统,实现的方法是使用消息队列。

。
在这种业务下我们最想要的是什么?
新闻顺序:对于同一个订单,状态变化有严格的顺序。
吞吐量:类似于订单业务,我们自然希望订单越多越好。订单越多吞吐量越大。
在这种情况下我们先看看 RabbitMQ 是怎么做的。
首先,发消息并向多个消费者广播这种情况RabbitMQ 它将为每个消费者建立相应的队列。也就是说,如果有 10 个人消费者RabbitMQ 会建立 10 对应的队列。然后,当一条消息发出时,RabbitMQ 这条消息将被复制 10 份放到这 10 个队列里。

。
当 RabbitMQ 将信息放入相应的队列后,我们面临的问题是,从消息队列中获取消息,我们应该在系统内启动多少线程。
如果只是单线程获取消息,自然没什么好说的。但是多线程情况可能会有问题......
RabbitMQ 有这样的特点,它在官方文档中声明,它不能保证同一队列的多线程消费,一定要保证顺序。不保证的原因,这是因为多线程时间,当线程消费信息报错时,RabbitMQ 消费失败的消息将再次进入团队,此时可能会出现乱序。

。
T0 时间,队列中有四条消息 A1、B1、B2、A2。其中 A1、A2 表示订单 A 两种状态:待付款,已付款。B1、B2 同样,是订单 B 待付款,已付款。
到了 T1 时刻,消息 A1 被线程 1 收到,消息 B1 被线程 2 收到。此时,一切都很正常。
到了 T3 时刻,B1 消费出错,同时,由于线程 1 处理速度快从消息队列中获取 B2。此时,问题开始出现。
到了 T4 时刻,由于 RabbitMQ 线程消费错误新闻可以重新入队的特点,此时 B1 队列头部将被重新放置。所以,如果不巧线程 1 获取到了 B1,乱序发生,B2 状态明明是 B1 后续状态,但是提前处理好了。
所以,你可以看到,这个场景用 RabbitMQ,三个问题:
- 发布订阅功能,复制使用的信息,降低性能,消耗更多资源。
- 许多消费者无法严格保证消息顺序。
- 大量订单集中在一个队列上c;吞吐量有限。
那么 Kafka 怎么样Kafka 就在这三个问题上,表现的要比 RabbitMQ 要好得多。
首先,Kafka 发布订阅不会复制新闻,因为 Kafka 发布订阅是指消费者直接获取订阅 Kafka 将消息保存在日志文件中。无论有多少消费者,他们只需要主动在文件中找到消息的位置。
二是,Kafka 消费者出错后不会出现,将新闻重新入队的现象。
最终,Kafka 订单可以分区,将不同的订单保存在多个分区中c;这样,吞吐量可以更好。
所以,对此需求 Kafka 更合适。
二、新闻匹配。
我曾经做过一套营销系统。这个系统有一个非常显著的特点,匹配规则非常复杂和灵活。
例如,宣传应根据推广内容以不同的方式进行匹配。再比如,分发应根据不同的活动匹配不同的渠道。
总之,在这个系统中,无数的匹配规则是一个非常重要的特征。

。
首先,先看看 RabbitMQ ,你会发现 RabbitMQ 允许在新闻中添加 routing_key 或者定制信息头然后通过一些特殊的 Exchange,新闻匹配分发的实现非常简单。开发几乎没有成本。
而 Kafka ?如果要实现消息匹配开发成本要高得多。
首先,不可能通过简单的配置自动匹配和分发给合适的消费者端。
二是,不管需要不需要,消费者必须首先要把所有的消息都放在#xff0上c;都取出来。然后,然后根据业务需求实现各种准确和模糊的匹配。也许是因为过度的复杂性,还需要引入规则引擎。
这个场景下 RabbitMQ 扳回一分。
三、信息超时。
电子商务业务,需求:下单后,如果用户在 15 分钟内未支付订单自动取消。
你可能会奇怪这种消息队列ñ怎么用?f;
先简单解释一下,单一服务系统,定时任务可以完成。
但是,在 SOA 或者在微服务架构下这样做是不可能的。因为很多服务都关心是否支付#xff0c;如果每个服务实现一套定时任务的逻辑,重复,又难以维护。
在这种情况下我们经常做一层抽象:将要执行的任务包装成新闻。时间到了直接扔进消息队列获取消息后的订阅者,可以直接执行。
希望将消息推迟一定时间处理,被称为延迟队列。
这类业务的订单取消,在创建订单时,我们将,同时,向延迟队列投掷包含执行任务信息的信息c;指定15分钟后,让所有订阅这个队列的消费者,你可以收到这个消息。随后,所有消费者所在的系统都可以执行扫描订单的相关任务。

。
RabbitMQ 和 Kafka 如何选择新闻队列?
先看下 RabbitMQ 的。
RabbitMQ 自带手表的消息c;消息中有个 TTL 字段,可以设置消息 RabbitMQ 存储时间,超时会被转移到一个叫死信队列的地方。
所以,延迟队列 RabbitMQ 最简单的实现方法是设置 TTL,然后一个消费者去监控死信队列。当消息超时,监控死信队列的消费者收到消息。
但是,这样做有个大问题:假设,我们先把一个过期时间放在队列里 10 秒的 A 新闻,再次放一个过期时间是 5 秒的 B 消息。 所以问题来了,B 消息会先于 A 消息进入死信队列,#xff1f;
答案是否定的。B 新闻将优先遵守先进先出的队列规则,在 A 新闻过期后与之一起进入死信队列被消费者消费。
在 RabbitMQ 的 3.5.8 版本后官方推荐的 rabbitmq delayed message exchange 插件可以解决这个问题。
- 使用此插件,当我们发送消息时,把消息发送到一个特殊的地方 Exchange。
- 同时,在消息头指定延迟时间。
- 收到消息的 Exchange 不会马上把消息放在队列里,相反,在消息延迟到达后,只有这样才能把消息放进去。

。
再看下 Kafka :

。
Kafka 实现延迟队列非常麻烦。
- 首先,你需要把消息放在一个临时的位置 topic。
- 然后你必须开发自己的中转消费者。让中间的消费者从这个临时消息开始 topic 取出来。
- 取出,这个消息不能马上处理,因为没有时间。也不能保存在自己的内存中,害怕崩溃,消息没了。所以,不到时间的消息必须存储在数据库中。
- 存储在数据库中的消息需要在时间到达后放入 Kafka 里,让真正的消费者实现真正的业务逻辑。
- ……。
想想就大了,这几乎是一个调度平台。再高级点需要时间轮算法才能更好更准确。
这次,RabbitMQ 上一个戴手表的消息,是最好的选择。
四、保留消息。
微服务,常用的事件溯源模式。如果你想用信息队列实现事件通常被视为新闻,依次发送到消息队列。
事件溯源有最经典的场景,这是事件的重放。简单来说,就是在处理之前依次取出系统中一段时间发生的事件。而且,不同的业务场景这些事件很可能不是一次性重放的,更有可能是重复 N 次。
假设,我们现在需要一批在线事件重播调查一些问题。
RabbitMQ 这个时候真的不行,因为消息被拿出来就被删除了。想再次被重复消费?对不起。
而 Kafka ,在一份特殊的日志文件中,新闻将持续下去。不会因为被消费而被删除。
所以,永不放弃消息 Kafka 使用后相对抛掷 RabbitMQ,请选择 Kafka。
五、错误处理消息。
很多时候在记录数据相关业务时,Kafka 一般是最好的选择。但是,有时候记录数据吞吐量不大的时候,我更喜欢自己用 RabbitMQ。
原因就是 Kafka 有一个我不喜欢的设计原则:
一旦单个分区的消息失败,我们只能停下来,而不是跳过这个失败的消息,继续消费后面的消息。也就是说,消息不允许空洞。
只要消息失败,不管是 Kafka 损坏自己的消息格式,还是消费者处理异常未来不允许跳过消费失败的消息继续消费。
所以,在。不需要非常准确的数据统计。选择了场景 Kafka,一旦出现消息消费问题,项目不可用的情况会发生。这真是徒增烦恼。
而 RabbitMQ ,当消息出现问题或消费错误时,它会,您可以重新加入或移动消息到死信队列,继续消费后面的,会省心很多。
坏消息就像群众中的坏人,Kafka 处理这个坏蛋太残忍了#xff0c;一定要把坏蛋拉出来。相对而言,,RabbitMQ 就温柔多了,群众坏蛋分开处理。
六、新闻吞吐量。
Kafka 每秒几十万消息吞吐,而 RabbitMQ 吞吐量是每秒数万条新闻。
事实上,公司内部有必须用到 Kafka 那么大吞吐量的项目真的很少。大部分项目像 RabbitMQ 每秒吞吐成千上万的消息,已经够了。
在一些吞吐量较小的项目中引入 Kafka,我认为最好介绍一下 RabbitMQ。
为什么?
因为 Kafka 为更好的吞吐量,在很大程度上增加了你的复杂性。对于项目来说,这些复杂性是#xff0c;麻烦,主要体现在两个方面::
1、复杂的配置和维护。
Kafka 参数配置相对 RabbitMQ 很复杂。例如:磁盘管理相关参数,集群管理相关参数,ZooKeeper xff00交互相关参数c;Topic 等级相关参数等都需要一些思考和调优。
另外,Kafka 自身集群和参与管理集群的集群 ZooKeeper,这就带来了更多的维护成本。Kafka 用好,你要考虑 JVM,持久消息,集群本身的互动#xff00c;以及 ZooKeeper 本身和它与 Kafka 它们之间的可靠性和效率。
2、用好,使用正确的存在门槛。
Kafka 的 Producer 和 Consumer 使用好本身也有很高的门槛。
例如,Producer 信息可靠性保证、权等性、事务信息等,都需要对 KafkaProducer 有深入的了解。
而 Consumer 更不用说了c;光是日志偏移管理就让很多人掉了很多头发。
相对而言,,RabbitMQ 就简单多了。你可能不需要配置任何,直接启动可以稳定可靠地使用。即使配置也可以设置几个参数。
所以,当每个人都在项目中引入新闻队列时,真的要好好想想,不要因为大家都提倡而提倡 Kafka 好,无脑引入。
总结。
你可以看到如果我们想做消息队列选择,有两件事必须做好:
列出业务最重要的特点。
深入比较消息队列的细节。
在我们非常熟悉这些中间件的特性之后,甚至可以将业务分解为不同的子业务,然后根据不同子业务的特点,引入不同的信息队列,也就是说,消息队列混用。这样,我们可能会最大化我们的利益,最小化我们的成本。
说了这么多,其实还是有很多的 Kafka 和 RabbitMQ 比较没有说,例如,两个集群的区别,占用资源的比较等。以后有机会再提。
总之,期待大家看完这篇文章后能对 Kafka 和 RabbitMQ 对差异有了更详细的了解。
最后,在网上分享一个比较完整的对比图:

。

。
