幂等性是数学和计算机科学中某些运算的性质,它们可以被多次应用,而不会改变初始应用的结果
在应用程序中,幂等性就是指对一个系统进行重复调用(相同参数),不论请求多少次,这些请求对系统的影响都是相同的效果
比如数据库的 select
操作。不同时间两次查询的结果可能不同,但是这个操作是符合幂等性的。
比如 i++
这个操作,就是非幂等性的
对于 MQ
而言,幂等性是指同一条消息,多次消费,对系统的影响是相同的
一般消息中间件的消息传输保障分为三个层级:
At most once
:最多一次。消息可能会丢失,但绝不会重复传输At least once
:最少一次。消息绝不会丢失,但可能会重复传输Excatly once
:恰好一次。每条消息肯定会被传输一次且仅传输一次RabbitMQ
支持“最多一次”和“最少一次”
对于“恰好一次”,目前 RabbitMQ
还做不到,不仅是 RabbitMQ
,目前市面上主流的消息中间件,都做不到这一点
在业务使用中,对于可靠性要求比较高的场景,建议使用“最少一次”,以防止消息丢失。“最多一次”会因为消息发送过程中,网络问题,消费出现异常等种种因素,导致消息丢失
以下场景可能会导致消息发送重复(包含但不限于)
Producer
意识到消息发送失败并尝试再次发送消息,Consumer
后续会收到两条内容相同并且 Message ID
也相同的消息Consumer
并完成业务处理,当客户端给服务端反馈应答的时候网络闪断。为了保证消息至少被消费一次,云消息队列 RabbitMQ
版的服务端将在网络恢复后再次尝试投递之前已经被处理过的消息,Consumer
后续会收到两条内容相同并且 Message ID
也相同的消息 但是“最少一次”就会造成一个问题,消息端会收到重复的消息,也会造成对同一条消息进行多次处理。一些不重要的业务还好一点,对于重要的业务,如果不对重复的消息进行处理,就会造成严重事故
MQ
消费者的幂等性的解决办法,一般有以下几种:
UUID
或者 MQ
消息中的唯一 ID
,但是一定要保证唯一性id
判断该消息是否已经消费过,如果已经消费过,则放弃处理ID
保存起来(数据库或 Redis
)可以使用
Redis
的原子性操作setnx
来保证幂等性,将唯一ID
作为key
放到Redis
中(setnx messageID1
)
在业务逻辑层面实现消息处理的幂等性
例如:通过检查数据库中是否已经存在相关数据记录,或者使用乐观锁机制来避免更新已经被其他事务更改的数据,再或者在处理消息之前,先检查相关业务的状态,确保消息对应的操作尚未执行,然后才进行处理,具体根据业务场景来处理
消息的顺序性是值消费者消费的消息和生产者发送消息的顺序是一致的
比如生产者发送的消息分别时 msg1
,msg2
,msg3
,那么消费者也是按照 msg1
,msg2
,msg3
的顺序进行消费的
很多业务场景下,消费是不用保证顺序的,比如使用 MQ
实现订单超时的处理。但有些业务场景,可能存在多个消息顺序处理的情况
一些资料显示 RabbitMQ
的消息能够保障顺序性,这是不严谨的。在
再不考虑系哦爱心丢失,网络故障等异常的情况下,如果只有一个消费者,最好也只有一个消费者的情况下,是可以保证消息的顺序性。但如果有多个生产者同时发送消息,无法确定消息到达 RabbitMQ Broker
的前后顺序,也就无法验证消息的顺序性
哪些情况可能会打破 RabbitMQ
的顺序性呢?下面介绍几种常见场景
ACK
) 丢失,从而使得消息被重新入队和重新消费,造成顺序性问题MQ
可能会认为消息未被成功消费而进行重试,这也可能导致消息处理的顺序性问题RabbitMQ
消息错序,如果要保证消息的顺序性,需要业务方使用 RabbitMQ
后做进一步处理消息顺序性保障分为:
局部顺序性通常指的是在单个队列内部保证消息的顺序;全局顺序性是指在多个队列或多个消费者之间保证消息的顺序
在实际应用中,全局顺序很难实现,可以考虑使用业务逻辑来保证顺序性
RabbitMQ
作为一个分布式消息队列,主要优化的是吞吐量和可用性,而不是严格的顺序性保证。如果业务场景确实需要严格的消息顺序,可能需要再应用层面进行额外的设计和实现
介绍来说一下消息顺序性保证的常见策略
最简单的方法是使用单个队列,并由单个消费者进行处理。同一个队列中的消息时先进先出的,这是 RabbitMQ
来帮助我们保证的
单个消费者的吞吐量太低了,当需要多个消费者以提高处理速度时,可以使用分区消费
RabbitMQ
本身不支持分区消费,需要业务逻辑趋势线,或者借助 spring-cloud-stream
来实现使用手动消息确认机制,消费者在处理完一条消息后,显式的发送确认,这样 RabbitMQ
才会移除并继续发送下一条消息
在某些情况下,即使消息乱序到达,也可以在业务逻辑层面实现顺序控制
RabbitMQ
本身并不保证全局的严格顺序性,特别是在分布式系统中。在实际应用开发中,根据具体的业务需求,可能需要结合多种策略来实现所需要的顺序保证
消息积压是指在消息队列(如 RabbitMQ
)中,将处理的消息数量超过了消费者处理能力,导致消息在队列中不断堆积的现象
通常有以下几种原因:
RabbitMQ
服务器配置偏低:消息积压可能会导致系统性能下降,影响用户体验,甚至导致系统崩溃。因此,及时发现消息积压并解决,对与维护系统稳定性至关重要遇到消息积压时,首要分析消息积压造成的原因,根据原因来调整策略
主要从以下几个方面来解决:
prefetchCount
,当一个消费者阻塞时,消息转发到其他未阻塞的消费者RabbitMQ
服务器的硬件,调整 RabbitMQ
的配置参数等上述这些策略选择时,需要总的考虑业务需求和系统的实际承载能力