简述:
RocketMQ是阿里巴巴开源的分布式消息中间件。支持事务消息、顺序消息、批量消息、定时消息、消息回溯。它里面有几个区别于标准中间件的概念。比如,Group、Topic、Queue。系统组成则有Producer、Comsumer、Broker、NameServer等等。
MQ的优缺点:
优点:
延迟很低(微秒级)
可靠性:使用一些机制来保证可靠性。比如:持久化、传输确认以及发布确认等。
灵活的路由:对于典型的路由,RocketMQ提供了一些内置的交换器来实现。针对更复杂的路由功能,可以将多个交换器绑定在一起,也可以通过插件机制来实现自己的交换器。
管理界面:RocketMQ提供了一个易用的用户界面,使得用户可以监控、管理消息,集群中的节点等。
高可用性:队列可以在集群的机器上设置镜像,使得部分节点在出现问题的情况下队列仍然可用。
多种协议:RabbitMQ除了原生支持AMQP协议,还支持STOMP、MQTT等多种消息中间件协议。
支持多种语言:如Java、Python、Ruby、PHP、C#、JavaScript等。
插件机制 : RabbitMQ提供了许多插件,以实现从多方面进行扩展,也可以自定义插件。
缺点:
erlang开发,难以维护
相对于其他中间件,吞吐量比较低。(万级)
RocketMQ由那些角色组成?每个人角色作用和特点是什么?
角色 | 特点 |
Producer | 消息生产者,负责发送消息到Broker |
Comsumer | 消息消费者,负责从Broker上拉取信息进行消费,消费完成进行ack |
Broker | 就是MQ本身,负责收发消息、持久化消息等。 |
NameServer | 无状态,动态列表;和zookeeper的重要区别之一。zookeeper有状态。 |
RabbitMQ消费模式包括哪些?
集群消费 | 一条消息会被同Group中的一个Comsumer消费 |
多个Group同时消费一个Topic时,每个Group都会有一个Comsumer消费到数据 | |
广播消费 | 消息将对一个Comsumer Group下的各个Comsumer实例都消费一遍。即使这些Comsumer属于一个Comsumer Group,消息也会被Comsumer Group中的每个Comsumer都消费一次 |
RabbitMQ消费消息是push还是pull?
RabbitMQ没有真正意义的push,都是pull。虽然有push类,但实现底层采用的是长轮询机制(拉取方式Broker端longPollingEnable标记是否开启长轮询,默认开启)
为什么主动拉取消息而不使用事件监听方式?
事件驱动方式是建立好长连接,由事件发送数据的方式来实时推送。
如果Broker主动推送消息的话可能push速度快,消费速度慢的情况,那么就会造成在consumer端堆积过多,同时又不能被别的consumer消费的情况。而pull的情况会根据自身情况来pull,不会造成过多的压力而造成瓶颈。所以采用了pull的方式。
RabbitMQ的使用场景
异步处理:用户注册后,发送邮件和注册短信。用户注册完成后提交任务到MQ,发送模块并行获取MQ中的任务。
系统解耦:比如某一个模块已经完成需要再加功能时,只要新增功能模块,从MQ中获取读取任务完成即可。无需改动原本模块的代码,这样原本的模块和新增模块通过MQ解耦。
流量削峰:秒杀和抢购等场景经常使用MQ进行流量削峰。流量暴增时,请求写入MQ超过MQ最大长度放弃请求,业务系统接受MQ中的消息进行处理,达到流量削峰,保证系统可用性的目的。
日志处理:日志采集方收集日志写入Kafka的消息队列中,处理方订阅并消费Kafka队列中的日志数据。
消息通讯:点对点或者订阅发布模式,通过消息进行通讯(微信的消息发送与接受,聊天室等)。
如何让RabbitMQ保证消息的顺序消费?
将多个消息发送在一个队列中,队列本身就是先进先出的结构
避免多消费者并发消费同一个queue中的消息
RabbitMQ如何保证消息不丢失?
Producer、Comsumer、Broker端都有可能出现丢失消息的情况。
Producer如何保证消息不丢失 | 采用send()同步发送消息,发送结果时同步感知的 |
发送失败后可以重试、设置重试次数,默认3次 | |
集群部署,发送失败的原因可能是当前Broker宕机了,重试时会发送到其他Broker上 | |
Broker端如何保证消息不丢失 | 修改刷盘策略为同步刷盘,默认是异步 |
集群部署,主从模式,高可用 | |
Comsumer端如何保证消息不丢失 | 完全消费成功后再进行收到ack确认 |
RabbitMQ的消息堆积如何处理?
消费者消费速度慢,或者出现了问题导致磁盘空间满、海量数据堆积,消费者需要很长时间消费。
磁盘空间满的情况:在其他机器上建立临时的消息队列,再写一个临时的消费者,把积压的消息放到临时队列里去
海量消息堆积的情况:修复消费者问题,停掉现有的消费者,临时建立10倍的消息队列,再用一个临时的消费者将消息分发到临时消息队列中,临时征用10倍的机器部署消费者。等积压消息消费完成后,再恢复成之前的架构
RabbitMQ为什么自研nameserver而不用zk?
1、RabbitMQ只需要一个轻量级的维护元数据消息的组件,为此引入zk增加维护成本还强依赖另一个中间件。
2、RabbitMQ追求的时AP,不是CP,就是高可用。
- zk就是CP,因为zk节点通过zap协议有数据共享每个节点数据会一致,但当zk集群挂了一半以上的节点就无法使用了。
- NameServer时AP,节点间不通信,导致节点间数据信息会发生短暂的不一致,但每个Broker都会定时向NameServer上报路由信息和心跳,当某个Broker下线时,NameServer30s后才会知道并且不会通知生产和消费者,只能靠客户端自己来拉。RabbitMQ是靠消息重试机制解决这个问题,所以是最终一致性。NameServer集群只要有一个节点就可用。
如何避免消息重复投递或者重复消费?
重复投递的原因:等待超时后需要重试
避免重复投递:
消息生产时,生成者发送的消息携带一个‘MessageID’(全局唯一ID),作于去重和幂等的依据,避免重复的消息进入队列。
重复消费的原因:
消费者接受消息后,在确认之前断开了连接或取消订阅。消息会被分发给下一个订阅的消费者
避免重复消费:
消息消费时,消息体必须携带一个全局唯一ID,作于去重和幂等的依据,避免同一条消息被重复消费。