目录
一、谈谈你对消息队列的理解
消息队列是一个按照先进先出原则的一个容器。用于对系统中产生的消息进行存放于消费。
消息队列的本质其实就是一个生成者-消费者模型。由生产者发送消息存储在消息队列中,消费从消息队列中获取。
二、消息队列的应用场景
异步处理:短信通知、app推送、用户注册等。
流量控制:比如在秒杀场景下,该商品的数量为100,当消息队列的数量达到100时,不再生产秒杀成功的消息,直接返回秒杀失败给用户。
服务解耦:生产者只管将数据分发给消息队列,而消费者只需要根据需求到消息队列中获取即可,不需要就取消消息队列的消费。
发布订阅:用户需要先去注册订阅消息,才能收到消息队列中的消息,进行消费。
高并发缓冲:将消息放入消息队列中,降低高峰数据对后端的短暂缓冲。
三、常见的消息队列有哪些
常见的消息队列一共有三种:RabbitMQ、RocketMQ、Kafka等。
RabbitMQ是基于erlang开发的消息队列,并发能力强、性能好、延迟低(可达到微秒级),单机的吞吐量可达到万级,基本不会丢失消息。
RocketMQ是基于java开发的消息队列,支持分布式部署,扩展性好,单机吞吐量可达到十万级,经过参数优化配置可做到0丢失。
Kafka功能简单,只支持基本MQ功能,它最大的优势在于专为超高吞吐量的实时日志采集,实时数据同步、实时数据计算等场景,单机吞吐量可达到十万级。
四、如何保证可靠性传输(消息不丢失)
消息队列也采用ACK确认机制,就是当消费者确认消息已经被消费处理,则会发送一个ACK给消息队列,消息队列在接收后就会删除这个消息了。
如果消费者宕机或者关闭,消息队列没有接收到ACK确认,则会认为这个消息没有被处理,会将这个消息从新发给其他消费者。
五、如何保证消息的完整性
通过事务机制,生产者可以将消息封装在同一个事务中,只有当所有操作完成,才会提交事务,如果某个操作失败,整个事务会进行回滚,从而保证消息的完整性和一致性。
六、如何保证消息不重复消费
当消息消费完毕后,消费者会发送一个ACK确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除,但如果消费者发送的消息因为网络传输等问题,没有发送给消息队列,消息队列无法确认消息是否被消费,就会继续将消息交给其他消费者。
解决方案(保证消息的唯一性,就算多次传输,不要让多次消费带来影响,保证消息的幂等性(用户对统一操作发生一次或多次的结果是一致的)):
1、消费一条消息就往数据库中插入一条数据,并设置唯一索引,如果一个消息被消费两次,就会因为数据的唯一索引导致插入失败,从而保证数据的正确性。
2、消费一条消息,在Redis中做set操作,set操作本身具备幂等性。
七、如何保证消息的顺序性
RabbitMQ:产生顺序错乱的原因是因为消费者通常是集群部署,多个消费者会同时执行不同消息,而执行的时间不同,导致最终执行binlog的顺序错乱。
解决方案:
创建多个队列。每个消费者固定消费一个队列的消息,生成发送消息时,同一个订单的消息发送到同一个队列中。
RocketMQ:每个Topic可以指定多个消息队列,当我写入消息时会把消息均匀发给不同的消息队列,而消费者同时在不同的消息队列中获取消息,由于执行速度不同,导致最终执行binlog的顺序错乱。
解决方案:
只需将同一个订单的消息发送到同一个消息队列即可。
Kafka:因为生成者在写入的时候会指定一个key,而通常我们会用订单号来做这个key,当消费者进行消费时,发现同一个key的多条消息,就会使用多线程处理,来提高速度,由于最终处理速度不同,执行binlog的顺序错乱。
解决方案:
可以在线程处理前,增加一个内存队列,将同一订单的消息放在同一个内存队列中,每个线程只负责一个内存队列。
八、MQ消息积压应该怎么处理
一般消息积压就是消息队列中大量消息,无法及时处理,消费。
解决办法的话就是:
增加消费端的数量,提高消息处理速度。
提高消费端的处理能力,可以采用多线程并发处理消息,或者采用分布式处理将消息分配多个消费者处理。
增加队列分区,可以将消费放在多个队列中。
设置超时机制,就是如果一个长时间没有处理,则对消息重新处理。
注:本篇文章都是我自己的理解,可能用词和语句不够严谨,如有错误请评论指正,谢谢!(持续更新中......)