消息重复的可能原因及解决办法

更新时间:

云消息队列 RabbitMQ 版中,消费重复(Message Duplication)指的是消费者在消费消息时,可能会多次接收到同一条消息。本文为您介绍消费重复的可能原因及解决办法。

可能原因

消费重复可能由以下原因导致:

  • 消息重推特性导致云消息队列 RabbitMQ 版为客户的消费过程设置了时长限制,当消费时长超出该限制时,消息将重新入队并推送。

  • 消费者崩溃或重启:如果消费者在处理消息的过程中崩溃或被重启,未能发送Ack消息,云消息队列 RabbitMQ 版服务端会认为该消息未被处理,从而重新分发给其他消费者。

  • Retry机制:请检查您的代码中,是否有某些业务逻辑或框架存在自动重试机制,从而导致重复消费相同消息。主要可以从消息轨迹、消息日志中判断同一条消息ID是否有多次发送的现象。

  • 服务端发布重启:请检查您实例所在地域的发布公告,检查消费重复问题出现时是否有发布,若有发布,则服务端重启可能会导致少量消息重复。

解决办法

问题定位

  1. 打开消息日志功能,针对消费重复的队列进行日志事件筛查。具体操作,请参见配置消息日志

    正常情况下,一条消息的生命周期应当由如下几个阶段组成:

    • SendMessage:消息发送事件。

    • PushMessage:消息从服务端推送给消费者的事件。

    • BasicAck:消费者确认消息消费完成,返回成功的事件。

    • DeleteMessage:服务端接收到Ack,删除消息成功的事件。

    根据上述几个事件可以作简单的自查:若消息发送事件仅向一个队列发送消息,且SendMessage与PushMessage的比例小于1,则代表消息有重复推送。若DeleteMessage的量少于PushMessage的消息量,则代表有消息Ack超时或消费失败。

    image

    如上图所示,DeleteMessage=BasicAck=PushMessage,代表该筛选条件下并无严重的消息重复问题。

  2. 针对重复消息ID,可以在日志中输入该ID,查看push事件的具体产生时间。

    image

    若如上图所示,则代表该消息始终未被有效消费,正在不断推送过程中。

  3. 若您的实例是企业版或者铂金版,则可以在Dashboard中查看消费时长统计,通过查看特定消费者的平均消费时长来判断消费ack是否及时。

    image

解决措施

  1. 把控消费时间:在消费过程中,每个队列的消费时长应严格遵循实例限制,且针对消费慢的队列需要做合理的QoS/Prefetch设置。例如一条消息的消费需要1分钟,实例的最大消费时长为5分钟,则Prefetch Count不能超过5条,否则一次拉取下来的消息便无法在5分钟内消费完成,后续拉下的消息也都将超时。

  2. 幂等性设计:业务逻辑可以设计为幂等操作,即相同的操作多次执行结果相同,这样可以避免因重复消费带来的问题。消费幂等的具体设置,请参见消息幂等

  3. 设置唯一消息ID:使用唯一的业务标识符(如订单ID、消息ID)来判断某操作是否已被处理。

  4. 消息去重:在消费端实现消息的去重逻辑,例如使用哈希表、Redis等存储已处理消息ID,对于重复的消息进行过滤。