SQS 队列中的确认消息

Posted

技术标签:

【中文标题】SQS 队列中的确认消息【英文标题】:Acknowledge message in SQS queue 【发布时间】:2018-04-02 11:52:41 【问题描述】:

我将 Amazon SQSAmazon SQS-JMS java 库与 Java EE 7 一起使用。我想要实现的是在收到消息后,具体取决于业务逻辑应用程序要么确认(使用)消息,要么再次将其重新发送到队列,并在 3 次重试失败后将其移至 DLQ。

我想在 JMS 中使用 CLIENT_Acknowledge 模式并且只确认成功处理的消息,但这是来自他们的官方文档:

在此模式下,当消息被确认时,在此消息之前收到的所有消息也会被隐式确认。例如,如果收到了 10 条消息,并且只有第 10 条消息被确认(按照收到消息的顺序),那么之前的 9 条消息也都被确认。

这个例子似乎也证实了这一点:http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/code-examples.html#example-synchronous-receiver-client-acknowledge-mode。

对我来说,这是一种奇怪的行为,与我对 client_acknowledge 的期望相反。这里有比仅仅根据进程状态手动将整个代码中的消息发送到主 SQS 队列或 DLQ 更优雅的解决方案吗?

【问题讨论】:

为什么要向队列重新发送消息?一条消息应该被消费和删除,或者不理会。您希望通过“确认”消息来实现什么目标? @JohnRotenstein 由于我第一次收到事件 B 时的业务逻辑,而不是 A,我想在处理事件 A 后将 B 返回到队列并处理它。另外我想使用重试计数和移动消息在 3 失败后到 DLQ,所以返回消息到队列是有意义的。 SQS 可以提供自己的 DLQ 逻辑。此外,如果您使用 SQS FIFO 队列,它可以保证排序。鉴于这些内置功能,我建议您不要重新处理消息 - 只需将它们拉出,处理它们,然后删除它们。 【参考方案1】:

要处理这种情况,您可以为您创建的 DLQ 使用 RedrivePolicy 属性。这种情况的解决方案可以是:

创建一个 2 个 sqs Qs 说 my_qmy_q_dl(后一个用于 DLQ) 使用RedrivePolicy将DLQ my_q_dl设置为my_q的DLQ。 在这里,应注意指定deadLetterTargetArnmaxReceiveCountmaxReceiveCount 是在将任何消息发送到 DLQ 之前,您希望在不确认的情况下处理任何消息的次数。如果您设置maxReceiveCount=3,则消息将保留在my_q 中,直到消费者第三次拉动而没有确认。 这里有2个案例: 正常情况:收到确认后立即删除 msg。 如果该消息第三次没有确认(消息删除),则该消息将从my_q 中删除并推送到 my_q_dl 自己。

*RedrivePolicy - 包含源队列的死信队列功能参数的字符串。

deadLetterTargetArn - Amazon SQS 在值之后将消息移动到的死信队列的 Amazon 资源名称 (ARN) 超过了 maxReceiveCount。

maxReceiveCount - 消息在被移动到死信队列之前被传递到源队列的次数。

注意 FIFO队列的死信队列也必须是FIFO队列。同样,标准队列的死信队列也必须是 标准队列。*

【讨论】:

那么当它是多个属性时,如何将 RedrivePolicy 格式化为字符串?作为 JSON 字符串。 SetQueueAttributesRequest 请求 = 新 SetQueueAttributesRequest() .withQueueUrl(src_queue_url) .addAttributesEntry("RedrivePolicy", "\"maxReceiveCount\":\"5\", \"deadLetterTargetArn\":\"" + dl_queue_arn + "\"" );【参考方案2】:

你可以使用:

UNORDERED_ACKNOWLEDGE

SQSSession.UNORDERED_ACKNOWLEDGE

来自 'com.amazon.sqs.javamessaging;'正如它在文档中所述,它是 Client_Acknowledge 的一种变体,它只确认调用它的消息。

 /**
 * Non standard acknowledge mode. This is a variation of CLIENT_ACKNOWLEDGE
 * where Clients need to remember to call acknowledge on message. Difference
 * is that calling acknowledge on a message only acknowledge the message
 * being called.
 */

依赖示例: “com.amazonaws:amazon-sqs-java-messaging-lib:1.0.3”

【讨论】:

非常感谢,一个更好的名字会节省很多时间。

以上是关于SQS 队列中的确认消息的主要内容,如果未能解决你的问题,请参考以下文章

如何将 SQS 队列订阅到 Java 中的 SNS 主题

当消息存在于 SQS 队列中时触发 AWS 中的 Lambda 函数

更长触发 lambda 的 SQS 消息

将 S3 事件订阅到 SQS 队列而不向世界公开 SQS?

确保对数据库和 SQS 的调用都成功

在发送到 SNS 之前,我可以使用 Amazon SQS 作为延迟队列吗?