Kafka与rabbitMQ的使用场景

一、消息的顺序

需求:当订单状态发生变化时,把订单状态变化的消息发送给所有关心订单变化的系统;

分析:

1、消息的顺序:对于同一笔订单来说,状态的变化是有严格的先后顺序的

2、吞吐量:像订单的业务,我们希望订单越多越好。订单越多,吞吐量越大

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

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

kafka:

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

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

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

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

二、消息的匹配

需求:不同的消息需要不同的消费者去消费 例如:某系统需要非常灵活的匹配规则;比如,要根据推广内容去匹配不同的方式做宣传。又比如,要根据不同的活动去匹配不同的渠道去做分发。

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

实现:Exchange根据 routing_key来路由发送到不同的queue,不同的系统订阅不同的queue即可;

kafka:如果你要实现消息匹配,开发成本高多了。

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

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

实现:不同的消费者组订阅同一个消费者,每一个消费者组中的某一个消费者会poll topic中的消息,但是这个消息可能不是当前系统需要消费的,需要规则匹配过滤掉不需要的消息,之前做过类似的是通过任务类型的map来维护的。

这个场景下 使用RabbitMQ 更加快捷。

三、消息的超时

需求:下单之后,如果用户在15分钟之内未支付,则自动取消订单;

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

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

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

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

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

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

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

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

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

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

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

kafka:

  • 你先需要把消息先放入一个临时的 topic。
  • 然后得自己开发一个做中转的消费者。让这个中间的消费者先去把消息从这个临时的 topic 取出来。
  • 取出来,这消息还不能马上处理啊,因为没到时间呢。也没法保存在自己的内存里,怕崩溃了,消息没了。所以,就得把没有到时间的消息存入到数据库里。
  • 存入数据库中的消息需要在时间到了之后再放入到 Kafka 里,以便真正的消费者去执行真正的业务逻辑。

想想就已经头大了,这都快搞成调度平台了。再高级点,还要用时间轮算法才能更好更准确。

这次,RabbitMQ 上那一条条戴手表的消息,才是最好的选择。

四、消息的保持

需求:事件的溯源。如果想使用消息队列实现,一般是把时间当成消息,依次发送到消息队列中。

事件溯源有个最经典的场景,就是事件的重放。简单来讲就是把系统中某段时间发生的事件依次取出来再处理。而且,根据业务场景不同,这些事件重放很可能不是一次,更可能是重复 N 次。加入我们现在有一批线上事故重放,去排查问题;

rabbitMq:消息被人取出来就删除了,想要再次重复消费时不可以的

kafka:消息会被持久化一个专门的日志文件里。不会因为被消费了就被删除。可以消费某一个offest的消息。

所以,对消息不离不弃的 Kafka 相对用过就抛的 RabbitMQ,请选择 Kafka。

五、消息的错误处理

很多时候,在做记录数据相关业务的时候,Kafka 一般是不二选择。不过,有时候在记录数据吞吐量不大时,我自己倒是更喜欢用 RabbitMQ。

原因就是 Kafka 有一个我很不喜欢的设计原则:

当单个分区中的消息一旦出现消费失败,就只能停止而不是跳过这条失败的消息继续消费后面的消息。即不允许消息空洞。

只要消息出现失败,不管是 Kafka 自身消息格式的损坏,还是消费者处理出现异常,是不允许跳过消费失败的消息继续往后消费的。

所以,在数据统计不要求十分精确的场景下选了 Kafka,一旦出现了消息消费问题,就会发生项目不可用的情况。这真是徒增烦恼。

而 RabbitMQ 呢,它由于会在消息出问题或者消费错误的时候,可以重新入队或者移动消息到死信队列,继续消费后面的,会省心很多。

坏消息就像群众中的坏蛋那样,Kafka 处理这种坏蛋太过残暴,非得把坏蛋揪出来不行。相对来说,RabbitMQ 就温柔多了,群众是群众,坏蛋是坏蛋,分开处理嘛。

六、消息的吞吐量

Kafka 是每秒几十万条消息吞吐,而 RabbitMQ 的吞吐量是每秒几万条消息。

其实,在一家公司内部,有必须用到 Kafka 那么大吞吐量的项目真的很少。大部分项目,像 RabbitMQ 那样每秒几万的消息吞吐,已经非常够了。

在一些没那么大吞吐量的项目中引入 Kafka,我觉得就不如引入 RabbitMQ。

为什么呢?

因为 Kafka 为了更好的吞吐量,很大程度上增加了自己的复杂度。而这些复杂度对项目来说,就是麻烦,主要体现在两个方面:

1、配置复杂、维护复杂

Kafka 的参数配置相对 RabbitMQ 是很复杂的。比如:磁盘管理相关参数,集群管理相关参数,ZooKeeper 交互相关参数,Topic 级别相关参数等,都需要一些思考和调优。

另外,Kafka 本身集群和参与管理集群的 ZooKeeper,这就带来了更多的维护成本。Kafka 要用好,你要考虑 JVM,消息持久化,集群本身交互,以及 ZooKeeper 本身和它与 Kafka 之间的可靠和效率。

2、用好,用对存在门槛

Kafka 的 Producer 和 Consumer 本身要用好用对也存在很高的门槛。

比如,Producer 消息可靠性保障、幂等性、事务消息等,都需要对 KafkaProducer 有深入的了解。

而 Consumer 更不用说了,光是一个日志偏移管理就让一大堆人掉了不少头发。

相对来说,RabbitMQ 就简单得多。你可能都不用配置什么,直接启动起来就能很稳定可靠地使用了。就算配置,也是寥寥几个参数设置即可。

所以,大家在项目中引入消息队列的时候,真的要好好考虑下,不要因为大家都鼓吹 Kafka 好,就无脑引入。

总结

可以看到,如果我们要做消息队列选型,有两件事是必须要做好的:

  1. 列出业务最重要的几个特点
  2. 深入到消息队列的细节中去比较

等我们对这些中间件的特点非常熟悉之后,甚至可以把业务分解成不同的子业务,再根据不同的子业务的特征,引入不同的消息队列,即消息队列混用。这样,我们就可能会最大化我们的获益,最小化我们的成本。

说了这么多,其实还有很多 Kafka 和 RabbitMQ 的比较没有说,比如二者集群的区别,占用资源多少的比较等。以后有机会可以再提提。

总之,期待大家看完这篇文章后,能对 Kafka 和 RabbitMQ 的区别有了更细节性的了解。

本文引用知乎上的一篇文章。

Kafka和RabbitMQ有哪些区别,各自适合什么场景? - 知乎

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KafkaRabbitMQ是两种流行的消息队列系统,用于实现异步消息传递。它们有一些相似之处,但也有一些重要的区别。 Kafka是由LinkedIn开发的分布式发布订阅消息系统,设计初衷是处理大规模的实时数据流。它使用高性能的持久化日志来存储消息,并提供高吞吐量和低延迟的数据处理能力。Kafka具有高可靠性、可伸缩性和容错性,并且支持水平扩展。它适用于大规模数据管道、实时流处理和日志聚合等场景RabbitMQ是一个开源的消息代理系统,实现了高度可靠的消息传递机制。它支持多种消息协议,包括AMQP、STOMP、MQTT等,并提供了丰富的功能和灵活的路由选项。RabbitMQ使用基于队列的消息模型,消息发送者将消息发送到队列中,而接收者则从队列中接收和处理消息。它适用于中小规模应用和复杂的消息路由场景。 两者之间的主要区别在于架构设计和适用场景Kafka的设计目标是高吞吐量和低延迟,适用于大规模数据处理和实时流处理。它将消息以日志文件形式持久化存储,支持多个消费者并行读取消息。RabbitMQ则更加注重消息传递的可靠性和灵活性,适用于中小规模应用和复杂的消息路由需求。 总的来说,选择Kafka还是RabbitMQ取决于你的具体需求。如果你需要处理大规模数据流、实时流处理或日志聚合等场景Kafka可能更适合。而如果你需要一个可靠的消息传递系统,并且对消息路由和协议的灵活性有较高的要求,那么RabbitMQ可能更适合。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值