【消息队列的定义】
消息队列是在消息的传输过程中保存消息的容器;
用于接收消息,并以文件的形式存储;
一个消息队列可以被一个或者多个消费者消费;
三个元素:
Producer:消息生产者,负责生产和发送消息到Broker;
Broker:消息处理中心,负责消息存储、确认、重试等;包含多个Queue;
Consumer:消息消费者,负责从Broker中获取消息,并进行相应处理;
过程描述:
1、消息生产者发送消息至MQ,等待MQ返回ACK;
2、MQ收到消息,将消息保存在MQ中;(先保存在内存,为了确保高可靠性,进行消息存盘,持久化到磁盘文件)
3、MQ消息存盘成功后,响应ACK给生产者;
4、MQ将消息推送给对应的消费者,等待消费者返回ACK;
5、如果消费者在指定时间内成功返回了ACK,则MQ判定消息消费成功,删除磁盘文件中的消息,执行步骤6;如果MQ在指定时间内没有收到ACK,则MQ判定消息消费失败,会尝试重试推送消息,重复执行4/5/6三步;
6、MQ删除磁盘文件中的消息;
文件系统:
1、落盘地点:部署MQ服务器的虚拟机/物理机的文件系统;
2、刷盘方式:异步刷盘和同步刷盘;
【刷盘原理】
以RocketMQ为例,详细分解异步刷盘和同步刷盘的原理:
适用场景:
同步刷盘:数据可靠性高,适用于金融等对数据可靠性要求高的场景,性能比较低;
异步刷盘:性能和吞吐量高,Broker端异常关闭时,会有少量消息丢失;
同步刷盘和异步刷盘的区别:
同步刷盘是消息写入内存的page Cache后,立即通知刷盘线程刷盘,然后等待刷盘完成。刷盘线程完成后唤醒等待的线程,返回消息写成功的状态;
异步刷盘是消息写入内存的page Cache后,立即返回写成功的状态,故而吞吐量大;当内存的page Cache积累到一定程度后,统一出发写磁盘动作,快速刷盘写入;
一般有两种,有两种方式进行读写
【思考题】(说明:下面以RabbitMQ为例)
1、生产者发送消息时,MQ如何防止丢失?
解决方案:
1.1 生产者发送消息确保成功:开启ACK机制;
(1)消息投递出去后,等待MQ响应一个ACK确认;
(2)如果没有ACK确认,在记录错误日志,然后开启重试;
1.2 MQ收到消息确保不丢失:开启持久化机制;
(1)消息队列的交换机要持久化;
(2)消息队列的队列要持久化;
(3)消息队列的消息要持久化;
(4)设置刷盘的规则,改用同步刷盘;
2、消费者消费消息时,MQ如何确保消费?
2.1 消费者消费消息确保成功:开启ACK机制;
(1)消息消费后,响应一个ACK确认给MQ,MQ收到ACK确认,则删除该消息;
(2)如果没有ACK确认,则将这个消息进入下一轮投递给其他消费者;或者加入死信/延迟队列;
2.2 通过业务逻辑确保消费成功:开启回调机制;
(1)消费者成功消费消息后,通过通知的方式告知生产者,则生产者不重推消息;
(2)如果在10分钟或者设定的时间内,没有通知,则生产者重推消息;
3、生产者推送消息时,如何解决重复推送消息?
(1)生产者业务逻辑中,严格根据ACK通知来记录好每条消息推送的结果,以此可以减少重复推送消息;
(2)消息体重自定义一个雪花算法的ID,以此标识消息的唯一性,在推送MQ前先将此消息的唯一标识入库或者暂存redis,然后推送消息时以此为标志判断是否推送成功;
4、消费者消费消息时,如何解决重复消费消息?
(1)根据生产者推送消息中的唯一性标识,消费者在消费的时候做好去重;(数据库表或者redis)
(2)消费者在消费消息时,考虑分布式部署的特点,需要根据消息唯一性标识添加分布式锁;
5、MQ如何保证消息顺序消费?
5.1为什么要顺序消费?
场景如:在用户下单之后,会发送创建订单、减扣库存的消息,但要保证减扣库存在创建订单之后执行;那就要求顺序消费了;
5.2 为什么会不按顺序消费?
由于消费者是集群部署,导致多个消费者能够消费同一个queue的消息;如果创建订单和减扣库存的消息都发送到同一个queue中,则不同的消费者就会有不同的顺序;
5.3 如何解决,确保消息顺序消费?
将Queue拆分,创建多个Queue,同类型的消息定义一个队列,然后创建多个消费者,每个消费者对应一个Queue;然后每个消费者在业务中使用分布式锁控制执行的顺序;
【消息队列模式】
点对点模式:多个生产者可以向同一个消息队列发送消息,一个具体的消息只能由一个消费者消费
发布/订阅模式:单个消息可以被多个订阅者并发的获取和处理
【消息队列应用场景】
1、应用解耦 :不同服务通过MQ进行通信,而不用关心彼此的实现细节;
2、异步处理:消息队列的生产者、消费者本来就异步;
3、削峰填谷:当上下游系统处理能力存在差距的时候,我们要严格要求自己
4、日志处理:(当大量的日志需要处理的时候,kafka是首选)
5、消息通讯:内置了高效的通信机制,因此可以在纯消息通讯、点对点消息队列,聊天室等功能谨慎使用;
6、消息广播:如果没有消息队列,每当一个新业务,都要接入一次新接口。
有兴趣的,可以私信我,进一步沟通交流!