IT袋

当前位置:主页 > 对比评测 >

Kafka和RabbitMQ到底怎么选

Kafka和RabbitMQ到底怎么选?(2)

时间:2024-03-24 12:00:26 来源:IT袋 作者:马勇
导读:Kafka和RabbitMQ到底怎么选,T0 时刻,队列中有四条消息 A1、B1、B2、A2。其中 A1、A2 表示订单 A 的两个状态:待付款、已付款。B1、B2 也同理,是订单 B 的待付款、已付款。 到了 T1 时

Kafka和RabbitMQ到底怎么选

Kafka和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,出现了三个问题:

  1. 为了实现发布订阅功能,从而使用的消息复制,会降低性能并耗费更多资源
  2. 多个消费者无法严格保证消息顺序
  3. 大量的订单集中在一个队列,吞吐量受到了限制

那么 Kafka 怎么样呢?Kafka 正好在这三个问题上,表现的要比 RabbitMQ 要好得多。

首先,Kafka 的发布订阅并不会复制消息,因为 Kafka 的发布订阅就是消费者直接去获取被 Kafka 保存在日志文件中的消息就好。无论是多少消费者,他们只需要主动去找到消息在文件中的位置即可。

其次,Kafka 不会出现消费者出错后,把消息重新入队的现象。

最后,Kafka 可以对订单进行分区,把不同订单分到多个分区中保存,这样,吞吐量能更好。

所以,对于这个需求 Kafka 更合适。

二、消息的匹配

我曾经做过一套营销系统。这套系统中有个非常显著的特点,就是非常复杂非常灵活地匹配规则。

比如,要根据推广内容去匹配不同的方式做宣传。又比如,要根据不同的活动去匹配不同的渠道去做分发。

总之,数不清的匹配规则是这套系统中非常重要的一个特点。

Kafka和RabbitMQ到底怎么选

首先,先看看 RabbitMQ 的,你会发现 RabbitMQ 是允许在消息中添加 routing_key 或者自定义消息头,然后通过一些特殊的 Exchange,很简单的就实现了消息匹配分发。开发几乎不用成本。

而 Kafka 呢?如果你要实现消息匹配,开发成本高多了。

首先,通过简单的配置去自动匹配和分发到合适的消费者端这件事是不可能的。

其次,消费者端必须先把所有消息不管需要不需要,都取出来。然后,再根据业务需求,自己去实现各种精准和模糊匹配。可能因为过度的复杂性,还要引入规则引擎。

这个场景下 RabbitMQ 扳回一分。

三、消息的超时

在电商业务里,有个需求:下单之后,如果用户在 15 分钟内未支付,则自动取消订单。

你可能奇怪,这种怎么也会用到消息队列的?

我来先简单解释一下,在单一服务的系统,可以起个定时任务就搞定了。

但是,在 SOA 或者微服务架构下,这样做就不行了。因为很多个服务都关心是否支付这件事,如果每种服务,都自己实现一套定时任务的逻辑,既重复,又难以维护。

在这种情况下,我们往往会做一层抽象:把要执行的任务封装成消息。当时间到了,直接扔到消息队列里,消息的订阅者们获取到消息后,直接执行即可。

希望把消息延迟一定时间再处理的,被称为延迟队列。

对于订单取消的这种业务,我们就会在创建订单的时候,同时扔一个包含了执行任务信息的消息到延迟队列,指定15分钟后,让订阅这个队列的各个消费者,可以收到这个消息。

随后,各个消费者所在的系统就可以去执行相关的扫描订单的任务了。

Kafka和RabbitMQ到底怎么选

RabbitMQ和Kafka消息队列如何选?

先看下 RabbitMQ 的。

RabbitMQ 的消息自带手表,消息中有个 TTL 字段,可以设置消息在 RabbitMQ 中的存放的时间,超时了会被移送到一个叫死信队列的地方。

所以,延迟队列 RabbitMQ 最简单的实现方式就是设置 TTL,然后一个消费者去监听死信队列。当消息超时了,监听死信队列的消费者就收到消息了。

不过,这样做有个大问题:假设,我们先往队列放入一条过期时间是 10 秒的 A 消息,再放入一条过期时间是 5 秒的 B 消息。那么问题来了,B 消息会先于 A 消息进入死信队列吗?

答案是否定的。B 消息会优先遵守队列的先进先出规则,在 A 消息过期后,和其一起进入死信队列被消费者消费。

在 RabbitMQ 的 3.5.8 版本以后,官方推荐的 rabbitmq delayed message exchange 插件可以解决这个问题。

  • 用了这个插件,我们在发送消息的时候,把消息发往一个特殊的 Exchange。
  • 同时,在消息头里指定要延迟的时间。
  • 收到消息的 Exchange 并不会立即把消息放到队列里,而是在消息延迟时间到达后,才会把消息放入。

相关阅读