消息队列的应用场景
数据结构:消息队列是一种先进先出的数据结构
应用场景:解耦、异步、削峰
解耦:各个系统之间耦合性高,如果某个子系统出现问题,会影响其他子系统和整个业务流程。这时引入消息队列,将子系统需要的数据放入消息队列,子系统出现异常,不会影响到其他子系统。
异步:某个子系统不依赖于其他子系统的返回结果。
流量削峰:秒杀系统请求流量瞬间激增,通过消息队列将请求缓存,可以提高系统的稳定性。
各种消息队列的比较
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
开发语言 | Java | Erlang | Java | Scala |
单机吞吐量 | 万级别 | 万级别 | 十万级别 | 十万级别 |
时效性 | ms级 | us级 | ms级 | ms级 |
可用性 | 高、主从架构 | 高、主从架构 | 非常高、分布式架构 | 非常高、分布式架构 |
ActiveMQ,早期使用的较多,没经过大规模吞吐量的验证,社区也不是很活跃,不推荐。
RabbitMQ,开源、性能稳定,推荐使用。
RocketMQ,开发语言是Java,推荐使用。
Kafka,大数据领域应用较多,日志采集业务推荐使用。
消息队列的优缺点
优点:解耦、异步、削峰
缺点:
系统可用性降低
保证消息队列高可用
系统复杂度提高
消息丢失
消息重复消费
消息传递顺序性
一致性问题
消息数据处理的一致性
如何保证消息队列的高可用
RabbitMQ高可用
-
普通集群
1.在多台机器上分别启动RabbitMQ实例
2.多个实例之间可以相互通信
3.创建的Queue只会放在一个RabbitMQ上,其他实例只同步queue元数据
4.消费时,如果连接的RabbitMQ没有Queue,当前实例会通过queue元数据拉取数据
特点:没有真正的做到高可用,数据拉取有时间开销,单实例的瓶颈问题。
-
镜像集群
1.在多台机器上分别启动RabbitMQ实例
2.多个实例之间可以相互通信
3.每次生产者写消息到queue的时候,都会自动把消息同步到多个实例的queue上,每个RabbitMQ节点上都有Queue的消息数据跟元数据。
RocketMQ高可用(双主双从)
1.生产者通过NameServer发现Broker
2.生产者发送消息到Broker主节点
3.Broker主节点跟从节点同步数据
4.消费者从主节点或从节点订阅消息
如何保证消息不丢失
消息丢失的原因:
1.消息生产者没有成功发送到MQ Broker
2.消息发送给MQ Broker后,Broker宕机导致内存中的消息丢失
3.消费者消费到了消息,但是没有处理完毕,客户端宕机
保证消息不丢失方案:
1.消息发送者发送给MQ Broker后,MQ Broker给生产者确认收到
2.MQ收到消息后进行持久化
3.消费者收到消息处理完毕后手动进行ack确认
4.MQ收到消费者ack确认后删除持久化的消息
如何保证消息不被重复消费(幂等性)
产生原因:
1.发送时消息重复:消息发送者发送给MQ Broker后,MQ Broker未给生产者发送确认收到消息,由于网络抖动,生产者未收到确认消息。
2.消费时消息重复 : 消费者收到消息处理完毕后,手动进行ack确认,由于网络抖动,MQ Broker未收到应答消息。
保证消息幂等性的方案:
1.消息发送者发动消息时携带一个全局唯一的消息ID
2.消费者获取消息后先根据id在redis/db中查询是否存在消费记录
3.如果没有消费就正常消费,消费完毕后写入redis/db
4.如果消息消费过就直接舍弃。
如何保证消息的顺序性
什么是消息的顺序性:消息有序是指按照消息发送的顺序消费。
保证消息顺序性方案:
全局顺序性:生产者、MQ Server、消费者按照1:1:1的配比,吞吐量比较低。
局部顺序性:生产者根据消息ID将同一组消息发送到同一个Queue中,多个消费者同时获取Queue中的消息进行消费。MQ使用分段锁保证单个Queue中的有序消费。【RocketMQ的方案】
消息堆积如何处理
消息堆积产生的原因:
1.由于网络抖动,消费者未及时消费消息
2.消费方处理消息后没有给MQ Server进行ack确认。
消息堆积处理方案:
1.检查消费方的正常消费速度
2.将堆积的消息转存到容量更大的MQ集群
3.增加多个消费者节点进行消费堆积消息
4.消费完毕后恢复原始架构
消息过期如何处理
什么是消息过期:为了保证消息不被积压,消息设置过期时间。
消息过期的处理方案:
1.过期消息放入死信队列
2.启动专门的消费者消费死信队列消息,并写入到数据库记录日志
3.查询数据库消息日志,重新发送消息到MQ