消息队列不是什么新鲜玩意了,网上也是一大堆消息队列的介绍。本文只记录自己消息队列的使用过程,和自己总结的消息队列的对比。
消息队列广泛应用主要得益于如下特性:
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、分区、索引文件等多种方式来实现高性能。文章来源:https://www.toymoban.com/news/detail-806935.html |
性能一般,主要其采用Push模式。文章来源地址https://www.toymoban.com/news/detail-806935.html |
到了这里,关于消息队列介绍与对比的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!