1.什么是消息队列?
Message:消息中间件,类似快递中间站,负责接受转发信息(这点同Nacos服务发现原理类似)
消息队列是分布式系统中重要的组件之一。使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。
2.消息队列作用?
- 通过异步处理提高系统性能(减少响应所需时间)。example:订单系统异步回调处理
- 削峰/限流 example:秒杀系统
- 降低系统耦合性。example:模块解耦,提高可维护性和扩展性
3.RocketMQ的安装
安装可以参考官网,根据自身电脑配置即可,这里不在赘述.
4.RocketMQ的消息模型
Producer Group
生产者组: 代表某一类的生产者,比如我们有多个秒杀系统作为生产者,这多个合在一起就是一个Producer Group
生产者组,它们一般生产相同的消息。Consumer Group
消费者组: 代表某一类的消费者,比如我们有多个短信系统作为消费者,这多个合在一起就是一个Consumer Group
消费者组,它们一般消费相同的消息。Topic
主题: 代表一类消息,比如订单消息,物流消息等等。
.RocketMQ的架构图
-
Broker
: 主要负责消息的存储、投递和查询以及服务高可用保证。说白了就是消息队列服务器嘛,生产者生产消息到Broker
,消费者从Broker
拉取消息并消费。 -
NameServer
: Broker管理 和 路由信息管理 。原理类似Nacos服务发现. -
Producer
:生产者, 消息发布的角色,支持分布式集群方式部署。 -
Consumer
:消费者,消费信息,支持分布式集群方式部署。
6.消息发送的三种模式
- 同步确认:消息发送后,生产者需收到确认结果才继续发布消息,(适用于短信通知等场景))
- 异步确认:消息一发送不等待结果发布新消息(一般用于链路耗时较长,对响应时间较为敏感的业务场景)
- 不确认(单向发布):适用于耗时短,可靠性要求不高的场景如日志收集等
7.消息类型:普通消息、顺序消息、延时消息、事务消息
顺序消息:在默认的情况下消息发送会采取Round Robin轮询方式把消息发送到不同的queue(分区队列);而消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序。当发送和消费参与的queue只有一个,则是全局有序;如果多个queue参与,则为分区有序,即相对每个queue,消息都是有序的。
example:一个订单的顺序流程是:创建、付款、推送、完成。订单号相同的消息会被先后发送到同一个队列中,消费时,同一个OrderId获取到的肯定是同一个队列。
延时消息:
## private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
Message msg = new Message(AppConstants.SMS_TOPIC, "user_reg", smsContent.getBytes("UTF-8"));
msg.setDelayTimeLevel(3);
RocketMQ支持不同Level的延时信息发送
8:分布式事务问题解决:事务消息加上事务反查机制
可参考官网的图
事务消息发送步骤如下:
- 发送方将half消息( 在事务提交之前,对于消费者来说,这个消息是不可见的 )发送至消息队列RocketMQ版服务端。
- 服务端确认half消息发送成功,(此时消息为half消息)。
- 发送方开始执行本地事务逻辑。
- 发送方根据本地事务执行结果向服务端提交二次确认(Commit或是Rollback),服务端收到Commit状态则将半事务消息标记为可投递,订阅方最终将收到该消息;服务端收到Rollback状态则删除半事务消息,订阅方将不会接受该消息。
事务消息回查步骤如下:
- 在断网或者是应用重启的特殊情况下,上述步骤4提交的二次确认最终未到达服务端,经过固定时间后服务端将对消息发送方即生产者集群中任意一生产者实例发起消息回查。
- 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
- 发送方根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行操作。
9.如何保证消费信息不丢失
Producer发送消息阶段:发送消息阶段涉及到Producer到broker的网络通信,存在消息丢失可能
解决:
1 提供SYNC的发送消息方式,等待broker处理结果。
-
同步发送:Producer 向 broker 发送消息,阻塞当前线程等待 broker 响应 发送结果。
-
异步发送:Producer 首先构建一个向 broker 发送消息的任务,把该任务提交给线程池,等执行完该任务时,回调用户自定义的回调函数,执行处理结果。
-
Oneway发送:Oneway 方式只负责发送请求,不等待应答,Producer只负责把请求发出去,而不处理响应结果。
我们在调用producer.send方法时,不指定回调方法,则默认采用同步发送消息的方式,这也是丢失几率最小的一种发送方式。
2
发送重试源码如下,本质其实就是一个for循环,当发送消息发生异常的时候重新循环发送。默认重试3次,重试次数可以通过producer指定。
3
broker提供多master模式,即使某台broker宕机了,保证消息可以投递到另外一台正常的broker上。
Broker处理消息阶段:刷盘策略和同步机制。
刷盘策略:
同步刷盘:在消息到达MQ后,RocketMQ需要将数据持久化,同步刷盘是指数据到达内存之后,必须刷到commitlog日志之后才算成功,然后返回producer数据已经发送成功。
同步刷盘是指数据到达内存之后,返回producer说数据已经发送成功。,然后再写入commitlog日志。
同步机制:
即使broker设置了同步刷盘,如果主broker磁盘损坏,也是会导致消息丢失。 因此可以给broker指定slave,同时设置master为SYNC_MASTER,然后将slave设置为同步刷盘策略。
此模式下,producer每发送一条消息,都会等消息投递到master和slave都落盘成功了,broker才会当作消息投递成功,保证休息不丢失
Consumer消费消息阶段
At least Once:Consumer先pull 消息到本地,消费完成后,才向服务器返回ack。
消费消息重试机制