为什么SQS消息有时会在队列上保持"未完成"状态

94

我正在非常简单的方式使用Amazon SQS队列。通常情况下,消息被写入后立即可见且可读取。偶尔会有一条消息被写入,但在队列中停留了几分钟而处于In-Flight(不可见)状态。我可以从控制台看到它。接收消息等待时间为0,且默认可见性为5秒。它会保持这种状态几分钟,或者直到某个新消息被写入并以某种方式释放它。几秒钟的延迟是可以接受的,但60秒以上就不可以。

有8个读线程始终长轮询,因此并不是没有尝试读取它,它们正在尝试。

编辑:明确一点,消费者读取都没有返回任何消息,无论控制台是否打开都会发生。在这种情况下,只涉及一条消息,它只是坐在队列中对消费者不可见。

有其他人遇到过这种情况吗?我该怎么做才能改善它?

这里是我正在使用的Java sdk:

<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk</artifactId>
  <version>1.5.2</version>
</dependency>     

以下是读取代码(最大值=10,最大等待时间=0,启动配置):

void read(MessageConsumer consumer) {

  List<Message> messages = read(max, maxWait);

  for (Message message : messages) {
    if (tryConsume(consumer, message)) {
      delete(message.getReceiptHandle());
    }
  }
}

private List<Message> read(int max, int maxWait) {

  AmazonSQS sqs = getClient();
  ReceiveMessageRequest rq = new ReceiveMessageRequest(queueUrl);
  rq.setMaxNumberOfMessages(max);
  rq.setWaitTimeSeconds(maxWait);
  List<Message> messages = sqs.receiveMessage(rq).getMessages();

  if (messages.size() > 0) {
    LOG.info("read {} messages from SQS queue",messages.size());
  }

  return messages;
}

当发生这种情况时,“read ..” 的日志行不会出现,这就是我需要使用控制台查看消息是否存在的原因,而它确实存在。


我遇到了同样的问题,请看看这是否有帮助 https://dev59.com/qHXYa4cB1Zd3GeqP9r6q - vijay
你能添加更多信息吗?例如,您是否使用标准的AWS SDK以及使用哪种语言?您能展示一下处理消息所使用的代码吗? - tster
@tster - 谢谢,我已经更新了问题并提供了更多细节。 - Jerico Sandhorn
我们现在面临着相同的问题 - 使用AWSSDK和JustSaying进行.Net开发,仍然不确定根本原因是什么,但症状是一致的。有更多细节时会更新此帖子。 - Darius
遇到了类似的问题。当使用 SQS 和 Lambda 时,当 Lambda 抛出运行时异常时,消息会保持在处理中状态 5 分钟。在这长达 5 分钟的等待之后,该消息将转移到死信队列。 - Judy007
@Judy007,你还在遇到这个问题吗?你找到解决方案了吗? - Dipanshu Mahla
2个回答

140

听起来你对所见到的内容有误解。

“In flight”消息并不是等待传递的消息,它们是已经被传递但尚未被消费者进一步处理的消息。

如果消息已发送到客户端但尚未被删除或尚未到达其可见性窗口的末尾,则认为该消息处于飞行状态。

https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html

当消费者接收到一条消息时,必须在某个时间点上要么删除该消息,要么发送请求以增加该消息的超时时间;否则,当超时时间到期后,该消息会重新变为可见状态。如果消费者未能执行其中之一,该消息将自动重新变为可见状态。可见性超时时间是消费者执行这些操作之前的时间。

消息不应该处于“in flight”状态,而没有任何东西已经接收到它们——但可以包括控制台本身,正如在选择“查看/删除消息”时看到的弹出窗口上所指示的那样(除非您已经选中“不再显示此内容”复选框):

控制台中显示的消息在控制台停止轮询消息之前不会对其他应用程序可用。

在从“查看/删除消息”屏幕观察队列时,控制台中显示的消息处于“in flight”状态。

不太合理的是,如果您的默认可见超时时间只有5秒,并且您的代码中没有增加该超时时间,那么消息在传递过程中“几分钟”仍保持悬浮状态... 然而,这可以被解释为消费者没有正确处理消息,导致其超时并立即重新投递,给人留下一个单独的消息实例仍然处于悬浮状态的印象,实际上,消息很快就会回到可见状态,然后立即被另一个消费者所获取,再次变为悬浮状态。


1
根据您对问题的描述,我的结论是您可能是通过控制台无意中引起了这个问题,或者您有一个正在监听队列的消费者您不知道,或者您与 SQS 接口的代码实际上会偶尔接收到消息并由于错误告诉您的应用程序未收到任何消息,因为您所描述的行为不应该发生,否则就给出“在飞行中”的定义。 - Michael - sqlbot
2
@JericoSandhorn,你曾经评论说“听起来这是我必须忍受的事情”,但这不对——我从未在SQS中看到过这种情况。我正在考虑你可以调查这个问题的方法,并想到了一些有趣的东西——在Cloudwatch中,选择“NumberOfMessagesReceived”和“NumberOfMessagesDeleted”的图表。你应该发现一个图表完美地覆盖并完全掩盖了另一个;如果它们在某种程度上没有这样做,那么强烈表明您使用的库或消费者存在问题,这将导致您观察到的症状。 - Michael - sqlbot
@sqlbot - 这是个好主意,但它们最终都会被删除,因为应用程序最终会读取并删除它们。问题在于长时间的延迟,而不是消息根本没有被读取。 - Jerico Sandhorn
当然可以……那么你可能没有理解这个练习的重点:一条消息只能被计算为“删除”一次,但可以被计算为“接收”多次,但前提是你的消费者并不是你认为的那样操作。如果你的计数器不匹配,问题就与你正在做的事情有关。 - Michael - sqlbot
1
@JasonSwett 这里的解决方案解决了 OP 没有完全理解“在飞行中”消息的事实。它们是您已经收到的消息。它们应该只是您当前正在处理的消息。如果您看到这个,那么您可能比您意识到的运行更多的消费者,或者您的代码中存在错误,您未能删除已处理的消息或重新排队。意外的“在飞行中”的消息基本上意味着您的代码正在“错放”它接收到的消息,在某个地方、某种方式下,在处理后未能对其进行操作。 - Michael - sqlbot
显示剩余9条评论

1
当你发送或锁定一条消息并在几秒钟内尝试获取最新的消息列表时,这种情况可能会发生。Amazon SQS将数据存储到多个服务器和多个数据中心,并保持高可靠性http://aws.amazon.com/sqs/faqs/#How_reliably_is_my_data_stored_in_Amazon_SQS
为了避免这些问题,您需要等待更长时间,以便队列有更多时间提供适当的结果。

Satish - 谢谢你..这听起来像是一个可行的理由。但是等待更长时间并不能真正解决问题,这就是现在默认发生的事情。听起来好像我必须接受使用 SqS 而不是像 AMQ 一样没有这些延迟的情况。 - Jerico Sandhorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接