如果我删除另一个消费者收到的 SQS 消息会怎样?
What happens if I delete an SQS Message that another consumer has received?
我怀疑有一个消费者处理给定消息的时间比默认消息可见性要长,但最终成功了。
- 如果
Consumer A
收到 R1M1
消息 M1
- 然后可见性超时结束
- 然后
Consumer B
收到消息 M1
的回执 R2M1
- 然后
Consumer A
调用 deleteMessage(R1M1)
消息是被删除了,还是保留在队列中,因为另一个消费者收到了更有效的消息收据?
我观察到我的队列中有许多更复杂的消息有很多 (50-1000) 个回执,但我没有记录任何处理消息的失败。我怀疑我多次成功处理每条消息,然后删除操作默默地失败了。
API 参考资料实际上自相矛盾on the same page。
DeleteMessage
Deletes the specified message from the specified queue. You specify the message by using the message's receipt handle and not the MessageId
you receive when you send the message.
Even if the message is locked by another reader due to the visibility timeout setting, it is still deleted from the queue.
这看起来很简单,直到您继续阅读。
Note
The receipt handle is associated with a specific instance of receiving the message. If you receive a message more than once, the receipt handle you get each time you receive the message is different. If you don't provide the most recently received receipt handle for the message when you use the DeleteMessage
action, the request succeeds, but the message might not be deleted.
因此,您的问题的答案是“是的,绝对是,但不是,不一定。”
但这确实解释了为什么您会出现静默失败——如果请求有效,删除显然不会失败。
这可能是 SQS 分布式特性的基本产物——如果 SQS 中传递消息的特定节点发生故障,则可能是旧的消息接收可能会丢失。当然,我只是在猜测。
不过,从根本上说,如果您遇到这种情况,您似乎确实存在设计缺陷。您要么发送后续请求以增加可见性超时,要么将默认可见性超时设置得足够高,以至于在正常情况下永远不会发生。最大值为 12 小时,对于大多数用例来说太长了。
此外,您的消费者需要一种方法来验证消息是否已被执行。
将可见性超时视为重试计时器。
我的基础架构中的一个示例是一个系统,该系统对被放入 S3 中的临时暂存存储桶中的文件做出反应。队列使用者查找文件,并进行一些数据库查询以确定哪个或哪些系统可能需要该文件。然后它将文件复制到目标系统的存储桶中,并且根据规则,它可能会创建数据库条目 and/or 将消息发送到不同的队列以处理该文件。这通常会在短短几秒钟内发生,如果一切顺利,消息将从队列中删除。如果出现问题,它只会忘记消息并返回轮询队列。
此队列的默认可见性超时设置为 5 分钟,这比该过程通常需要的时间长得多,因为这是我希望在处理失败时重试消息的时间。这就是您要使用可见性超时的方式。
请注意,在标准处理条件下,正常模式处理永远不需要 5 分钟。
5次重试后,SQS将消息从主队列中移除,并将消息放入死信队列(你可以选择数字,我的设置是5)。这个队列由一个单独的进程使用,该进程存储消息并提醒我这个消息已经超过了它允许的接收数量并且它从未被删除 - 表明毒丸消息或某种未处理的错误或慢性故障情况。
我怀疑有一个消费者处理给定消息的时间比默认消息可见性要长,但最终成功了。
- 如果
Consumer A
收到R1M1
消息M1
- 然后可见性超时结束
- 然后
Consumer B
收到消息M1
的回执 - 然后
Consumer A
调用deleteMessage(R1M1)
R2M1
消息是被删除了,还是保留在队列中,因为另一个消费者收到了更有效的消息收据?
我观察到我的队列中有许多更复杂的消息有很多 (50-1000) 个回执,但我没有记录任何处理消息的失败。我怀疑我多次成功处理每条消息,然后删除操作默默地失败了。
API 参考资料实际上自相矛盾on the same page。
DeleteMessage
Deletes the specified message from the specified queue. You specify the message by using the message's receipt handle and not the
MessageId
you receive when you send the message.Even if the message is locked by another reader due to the visibility timeout setting, it is still deleted from the queue.
这看起来很简单,直到您继续阅读。
Note
The receipt handle is associated with a specific instance of receiving the message. If you receive a message more than once, the receipt handle you get each time you receive the message is different. If you don't provide the most recently received receipt handle for the message when you use the
DeleteMessage
action, the request succeeds, but the message might not be deleted.
因此,您的问题的答案是“是的,绝对是,但不是,不一定。”
但这确实解释了为什么您会出现静默失败——如果请求有效,删除显然不会失败。
这可能是 SQS 分布式特性的基本产物——如果 SQS 中传递消息的特定节点发生故障,则可能是旧的消息接收可能会丢失。当然,我只是在猜测。
不过,从根本上说,如果您遇到这种情况,您似乎确实存在设计缺陷。您要么发送后续请求以增加可见性超时,要么将默认可见性超时设置得足够高,以至于在正常情况下永远不会发生。最大值为 12 小时,对于大多数用例来说太长了。
此外,您的消费者需要一种方法来验证消息是否已被执行。
将可见性超时视为重试计时器。
我的基础架构中的一个示例是一个系统,该系统对被放入 S3 中的临时暂存存储桶中的文件做出反应。队列使用者查找文件,并进行一些数据库查询以确定哪个或哪些系统可能需要该文件。然后它将文件复制到目标系统的存储桶中,并且根据规则,它可能会创建数据库条目 and/or 将消息发送到不同的队列以处理该文件。这通常会在短短几秒钟内发生,如果一切顺利,消息将从队列中删除。如果出现问题,它只会忘记消息并返回轮询队列。
此队列的默认可见性超时设置为 5 分钟,这比该过程通常需要的时间长得多,因为这是我希望在处理失败时重试消息的时间。这就是您要使用可见性超时的方式。
请注意,在标准处理条件下,正常模式处理永远不需要 5 分钟。
5次重试后,SQS将消息从主队列中移除,并将消息放入死信队列(你可以选择数字,我的设置是5)。这个队列由一个单独的进程使用,该进程存储消息并提醒我这个消息已经超过了它允许的接收数量并且它从未被删除 - 表明毒丸消息或某种未处理的错误或慢性故障情况。