消息队列介绍与对比

        消息队列不是什么新鲜玩意了,网上也是一大堆消息队列的介绍。本文只记录自己消息队列的使用过程,和自己总结的消息队列的对比。

        消息队列广泛应用主要得益于如下特性:

        1、非实时性。一些业务并不需要实时处理;

        2、异步。不需要同步进行处理不同业务,可异步去处理;

        3、解耦。将不同业务进行分离,生产者和消费者相互独立。

        4、流量削峰,限流缓解高并发。比如在秒杀中,经常会用到消息队列进行排队,缓解高并发压力。

        市面上开源的消息有很多,我最早接触的是RabbitMQ,因为当时自己网站用了celery,其内部就是使用了RabbitMQ,后来在2018年要换工作,去小米之前接触了golang的nsq,进入小米之后又开始使用了Kafka,过了两年,业务系统全部换成RocketMQ。就这样,我几乎把比较著名的消息队列都使用了一遍。总结一下我使用的场景:

       RabbitMQ:Celery,用于任务发布和消费执行,在我个人网站有充分应用;

       Kafka:早期小米有品订单支付后发送通知给小米OC,后期只使用Kafka做日志传输;

      NSQ:这个我纯粹是从学习的角度熟悉的,没有在实际工作中使用;

      RocketMQ:这个应该是我在实际工作中使用最多的,当年在小米几乎所有业务系统都使用RocketMQ作为唯一的业务消息中间件。

       Notify:这个是小米自研的,我们最早用过一段时间,说实话,我不是贬低他,但性能差得远了,最早版本是使用Mysql实现的,后来还是要借助RocketMQ,也就是说本身没什么意义了。 

     当我们在写业务中,如何做技术选型还是要因地制宜,从实际业务场景去出发,而不是一概而论。因为每个消息队列都有其特性,都会侧重其中某些方面。就像在小米时后来都选用RocketMQ时因为其更适用于我们电商的场景,其支持消息延迟、定时、半事务消息等等。而并不是说其他的不好。我现单位的EDA也是基于RocketMQ开发的。

        那做消息队列选型,就要从以下几个维度去考虑:

  • 消息顺序
  • 消息重复/消息幂等
  • 消息丢失
  • 消息事务
  • 消息延迟
  • 消费优先级
  • 消费持久化
  • 消息回溯  

          举个例子,如果对消息的丢失很看重,就一定注意持久化的问题。我们知道RabbitMQ的队列默认是auto-delete的,如果服务器重启了,队列都没了。我现单位就有一个项目组使用了RabbitMQ就出现了这个问题,服务器down掉后,重启后导致之前需要发送的消息全部丢失,这就是对消息队列不熟悉导致的。

类型

RocketMQ

Kafka

Rabbitmq

消息重复/幂等

不保证消息重复,需要在消费端自行实现。

早期版本不保证消息重复,需要在消费端自行实现。自从0.11.0.0之后,可实现生产消息不重复,Exactly Once。小米之前还发了一个基于Kafka的Talos,实际上也是通过生成唯一id保证的。

不保证消息重复,需要在消费端自行实现

消息持久化

支持,持久化到文件

RocketMQ的文件是存在commitLog,顺序写,通过mmap零拷贝技术提升读写性能,当然也有一个Index File索引文件,这个和Kafka差不多的

支持,持久化到文件。和RocketMQ的定长文件不同,Kafka的文件分区存储。

需要配置队列和消息的持久化。

消息丢失

可以保证at least once ,因此不会丢失。

在生产端,只有broker回复SUCCESS,生产端才为投递成功;

在消费端,只有回传SUCCESS给broker,才被认为消费成功。

当然,发送模式应该是同步活异步,如果发送模式选择oneway则不保证。

但有一种情况可能出现丢失:broker集群收到消息了,但是采用异步刷盘的话,可能在落盘之前,整个集群都挂掉了,当然发生概率会很低。

同理,也可保证消息不丢失。其实RocketMQ也是参考kafka来实现的。同样在生产消息以及消费消息的过程都会有确认机制。

可以保证不丢失

但是 队列和消息都要配置持久化,否则只在内存中,还是有可能丢失的。

消息顺序

在同一个逻辑队列中,可以实现消息的顺序。全局也可以,但是效率较差。

当使用顺序消息时,消费端同样要改成顺序消费,其默认是并发消费,即会同时开多个线程并发消费。

同一个partition下的可以实现消息顺序。

同理,将要顺序消费的消息放在一个Queue

消息延迟

支持延迟,延迟实现的方式(开源版)是设置不同级别的延迟队列,队列中通过定时去处理到期消息,其共有18个级别的定时。

在到时之前投递在一个专门的TOPIC下。

这个地方,小米后来是借助滴滴方式实现了任意时间的延迟。

这里要说一下,商业版是支持任意时间,嗯,阿里很会玩儿。

不支持。但内部通过时间轮实现了定时任务,不对外提供相应功能。

本身不支持,但可通过延迟插件或者死信队列方式实现。可以访问下面的参考资料

消息回溯

由于最后文件是写到磁盘文件,是支持消息回溯的。但过期删除的查看不了,一般上可配置7天或一个月。

支持回溯,支持按照offset和timestamp两种维度进行回溯。

不支持,当消息被消费之后,就会被删除。

消息事务

支持在生产者和broker之间的半事务。具体流程可参考官网。简单说就是通过双方的commit,以及事务状态回查来实现。

在事务完全提交之前,是个半事务消息,也不会消费。

自0.11开始,kafka就支持了事务。但这个事务和RocketMQ的事务不是一回事,RocketMQ强调分布式事务的场景。Kafka强调的是一次发多个消息的事务特性。即多个消息要么都成功,要么都失败。

虽然Rabbitmq事务机制,但感觉其并非为了支持分布式事务,而只是一种支持At least once的保证机制。

消费重试

集群模式下,如果未成功消费,可以重试,超过一定次数进入死信队列;

广播模式下,不支持重试。

不支持。和RocketMQ不同,kafka不需要消费者提供消费ack,而且不自动维护偏移量,只是提供偏移量更新接口。不过可以根据这个特性实现自动重试。

支持。默认支持消费端的确认机制。

消费分组

支持消费分组

支持消费分组

不支持,一个消息只能被一个消费者消费

高可用

设置NameServer集群,每个节点都会存储全部的路由和topic信息。

broker集群:多master+多slave

且 broker有专门负责master到slave的同步

集群部署,早期使用ZK管理。后期自实现KRaft进行集群管理。

有主队列和镜像队列,可以保证高可用。但要特别注意集群内的节点同步只同步队列元数据,不同步队列数据本身,RabbitMQ主要是基于性能考虑。

高性能

通过顺序IO、零拷贝mmap)、PageCache、分区、索引文件等多种方式来实现高可用。

支持消费端多线程并发消费。

通过顺序IO、零拷贝(sendfile)、PageCache、分区、索引文件等多种方式来实现高性能

性能一般,主要其采用Push模式

你可能感兴趣的:(消息队列,rocketmq,rabbitmq,kafka)