我以一种非常简单的方式使用 Amazon SQS 队列。通常,消息是写入的,并立即可见和读取。偶尔会写入一条消息,并在队列中保持"正在进行(不可见)"几分钟。我可以从控制台看到它。接收消息等待时间为 0,默认可见性为 5 秒。它将保持这种状态几分钟,或者直到写入新消息以某种方式释放它。延迟几秒钟是可以的,但超过 60 秒是不行的。
有 8 个阅读器线程总是在长时间轮询,所以不是有什么东西没有试图阅读它,而是它们。
编辑 :需要明确的是,所有使用者读取都没有返回任何消息,无论控制台是否打开,都会发生这种情况。在此方案中,仅涉及一条消息,它只是位于使用者不可见的队列中。
有没有人看到过这种行为,我可以做些什么来改进它?
这是我正在使用的java的sdk:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.5.2</version>
</dependency>
以下是执行读取的代码(max=10,maxwait=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://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html
当使用者收到消息时,它必须在某个时候删除该消息,或者发送请求以增加该消息的超时;否则,该消息在超时到期后再次可见。 如果使用者未能执行这些操作之一,则消息将自动再次可见。 可见性超时是使用者在必须完成其中一项操作之前的时间。
消息不应该在没有收到的情况下"正在传输",但"某些东西"可以包括控制台本身,正如您在控制台中选择"查看/删除消息"时看到的弹出窗口中指出的那样(除非您已经选中了"不再显示"复选框):
控制台在控制台停止轮询消息之前,控制台中显示的消息将不可用于其他应用程序。
中显示的消息处于"传输中"状态,而控制台正在从"查看/删除消息"屏幕观察队列。
没有明显意义的部分是消息在"几分钟"中运行,如果您的默认可见性超时仅为 5 秒,并且您的代码中没有任何内容会增加该超时......然而。。。这几乎可以完美地解释为您的消费者没有正确处理消息,导致它超时并立即重新传递,给人的印象是消息的单个实例仍在传输中,而实际上,消息正在短暂地转换回可见,只是几乎立即被另一个消费者认领, 再次将其带回飞行中。
当您发送或锁定消息并在几秒钟内尝试获取新的消息列表时,可能会发生这种情况。Amazon SQS 将数据存储在多个服务器和多个数据中心 http://aws.amazon.com/sqs/faqs/#How_reliably_is_my_data_stored_in_Amazon_SQS 中。
要摆脱这些问题,您需要等待更多时间,以便队列有更多时间给出适当的结果。