目录
1.幂等性保障
2.顺序性保障
3.消息积压
1.幂等性保障
(1)介绍幂等性
幂等性,最早期是数学和计算机科学中某些运算的性质,它们可以被多次应用,而不会改变初始应用的结果
比如说,重复多次调用同一个函数,函数返回的结果也相同。
比如,牛羊吃进去的是草,拉出来的也是
(2)MQ上的幂等性
定义:对于MQ的幂等性,是指同一条消息,进行多次消费,对系统的影响的相同的
为什么会有同一个消息多次消费,是因为可能触发重试等机制
所以对于消息中间件,对消息传输保障分为三个层级:
1)At most once:最多一次。消息可能会丢失,但绝不会重复传输。
2)At least once:最少一次。消息绝不会丢失,但可能会重复传输。
3)Exactly once:恰好一次。每条消息肯定会被传输一次且传输一次。
对于目前的中间件来说,只能支持前面两种,最后一种也无法做到。
(3)MQ如何保障幂等性
为什么要保证幂等性?
比如用户下单一个商品,在支付页面因为网络缘由,多次点击,这个时候就只能认为是一次消费。
所以幂等性保障,就是可以正确的处理相同重复的消息。对于RabbitMQ保障幂等性有两个方面:保证全局ID和代码逻辑判断,主要方法还是需要靠全局唯一ID
1)全局唯一ID
做法:给每条消息分配一个全局唯一的ID。这个ID可以自定义生成,比如UUID,UUID+时间戳等。
当消费者收到消息后,就可以根据唯一ID判断该消息是否已经被消费过,如果已经被消费观过,则可以不做处理,进而可以避免重复消费的问题。
对于未消费过的消息,就可以进行消费;在消费完成后,就需要把该ID进行保存起来,表明该ID的消息已经被消费过。
2)业务逻辑判断
这个方面就考验程序猿的代码能力了。比如通过检查数据库中是否已经存在相关的数据记录;或者在处理消息前,检查相关业务的状态,确保消息对应的操作尚未执行,然后再进行处理。
2.顺序性保障
顺序性保障,是指消费者消费的消息和生产者生产的消息顺序一致。
对于很多的业务场景,对顺序性是没有要求的;但是一些场景下是有要求的,比如对同一个用户的同一个信息进行修改。
(1)会打破顺序性的场景
1)多个消费者
当存在多个消费者的时候,消息被哪一个消费者消费是不确定的,也可能并行处理,就会导致消息的顺序性无法保证
2)网络波动或异常
在消息传递过程中,如果出现网络波动或者异常,可能导致消息会重新入队,进行直接影响顺序性。
3)消息重试
消费者消费完成后没有及时对消息进行确认,或者确认丢失,MQ可能认为消息未发送成功进而重试,也会导致消息处理的顺序性问题。
4)消息路由问题
消息会根据不同的路由规则进入不同的队列,因为每个队列的情况都会不太一样,就无法保证全局的顺序性。
5)死信队列
当消息因为一些原因进入死信队列后,再被消费者消费,就无法保证消息的顺序性和生产者发送消息的顺序一致。
上述的比较常见的场景,如果需要保障顺序性,就需要做出相应的处理。
(2)如何保障顺序性
消息顺序性保障分为:局部顺序性保障和全局顺序性保障。一般都为局部性保障,全局性保障较为困难。
- 局部顺序性保障:指的是在单个队列内部保证消息的顺序
- 全局顺序性保障:指的是在多个队列或者多个消费者之间的顺序性保障
下面介绍两个常用的顺序性保障策略
1)单个消费者和单个队列
这样的策略下,就能从很大的几个方面下杜绝了一些情况,进而跟容易保障消息的顺序性问题。
2)分区消费
这里的分区指的是将一个队列划分成多个区域,每个区域引入一个消费者进行消费,这个时候保障每个分区内的顺序性即可。
3)消息确认机制
使用手动消息确认机制,消费者在处理完⼀条消息后,显式地发送确认,这样RabbitMQ才会移除并继续发送下⼀条消息.
4)业务逻辑控制
在某些情况下,即使消息乱序到达,也可以在业务逻辑层⾯实现顺序控制,比如通过在消息中嵌入序列号,并在消费时根据这些信息来处理
3.消息积压
消息积压,指的是在消息队列中,待处理的消息数量超过了消费者的处理能力,导致消息在队列中不断堆积的现象。
(1)产生的原因
- 消息生产过快
在高流量或者高负载的情况下,生产者以极高的速率发送消息,超过了消费者的处理能力,这也就是本质原因
- 消费者处理能力不足
- 消费端业务逻辑复杂,耗时长
- 消费端代码性能低
- 系统资源限制,如CPU、内存、磁盘I/O等也会限制消费者处理消息的效率
- 异常处理不当。比如消费者在处理消息时出现异常,导致消息无法被正确处理和确认
- 网络问题
比如网络延迟或不稳定,消费者无法及时接收或者确认消息,最终导致消息积压
- RabbitMQ服务器配置偏低
消息积压会导致系统性能下降,影响用户体验,甚至导致系统崩溃
(2)解决方案
- 提高消费者效率
- 增加消费者实例数量,比如多引入新的机器
- 优化业务逻辑,比如使用多线程来处理业务
- 设置prefetchCount,当一个消费者阻塞时,消息转发到其他未阻塞的消费者中
- 消息发送异常时,设置合适的重试策略,或者转入死信队列
- 限制生产者速率
- 流量控制:在消息生产者中实现流量控制逻辑,根据消费者处理能力动态调整发送速率
- 限流:使用限流工具,为消息发送速率设置一个上限
- 设置过期时间:如果消息过期未消费,可以配置死信队列,以避免消息丢失,并减少对主队列的压力
- 资源与配置优化
比如升级RabbitMQ服务器的硬件,调整RabbitMQ的配置参数等