亚马逊 SQS 长轮询未返回所有消息

12

我有一个需求,需要在1次读取中读取我的Amazon SQS队列中的所有消息,然后根据创建时间戳对其进行排序并执行业务逻辑。

为了确保检查所有SQS主机的消息,我启用了长轮询。 我的做法是将队列的默认等待时间设置为10秒钟。(任何大于0的值都将启用长轮询)。

然而,当我尝试读取队列时,它仍然没有给我所有的消息,我不得不多次读取才能获得所有的消息。 我甚至通过每个接收请求的代码启用了长轮询,但仍然无效。 以下是我使用的代码。

AmazonSQSClient sqsClient = new AmazonSQSClient(new ClasspathPropertiesFileCredentialsProvider());
sqsClient.setEndpoint("sqs.us-west-1.amazonaws.com");
String queueUrl = "https://sqs.us-west-1.amazonaws.com/12345/queueName";
ReceiveMessageRequest receiveRequest = new ReceiveMessageRequest().withQueueUrl(queueUrl).withMaxNumberOfMessages(10).withWaitTimeSeconds(20);
List<Message> messages = sqsClient.receiveMessage(receiveRequest).getMessages();

我的队列中有3条消息,每次运行代码时结果都不同,有时我会收到全部3条消息,有时只有1条。我将可见超时设置为2秒,仅为了排除消息在读取时变为不可见的原因。 这是短轮询的预期行为。长轮询应该消除多次轮询。我在这里做错了什么吗?

谢谢

4个回答

29
长轮询的目的是消除多次轮询。
不,长轮询的目的是消除大量的空轮询和虚假的空响应,当有消息可用时。SQS中的长轮询不会一直等待最长等待时间来查找更多要返回的内容,或者在找到某些东西后继续搜索。SQS中的长轮询仅等待足够长的时间以找到“某些东西”:
“长轮询允许Amazon SQS服务在发送响应之前等待队列中有消息可用。因此,除非连接超时,ReceiveMessage请求的响应将包含至少一个可用的消息(如果有)并最多包含ReceiveMessage调用中请求的最大数量。” -- http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-long-polling.html (重点添加)
因为SQS是一个分布式系统,所以它找到并返回的“something”可能是所有消息(最多达到您设置的上限)或消息的子集。可能需要在“尽快返回找到的内容”和“搜索整个系统以获取客户端接受的最大数量的所有内容”之间做出架构决策……考虑到这些选择,似乎大多数应用程序都更喜欢更快的响应,“尽可能快地给我你能找到的任何东西”。只有当您从长轮询收到空响应时,才知道您是否已经排空队列。

1
从长轮询中获得空返回并不保证队列为空。更好的指示是在请求队列中的消息数量时获得0,但这也不能保证。 - tster
@tster 我从来没有遇到过这样的情况,即使队列中有消息,在长轮询返回0个消息,尽管这在理论上是可能的。但是,这与文档中记录的断言相矛盾,即如果有任何可用消息,则“长轮询响应将包含至少一个可用消息”。如果发生这种情况,那应该是例外情况。 - Michael - sqlbot
长轮询应配置多长等待时间?我们如何知道设置的时间间隔足以确保 SQS 没有更多的消息? - Andy Dufresne

2
正如Michael - sqlbot所指出的,即使使用长轮询,SQS也不能保证返回所有(或请求的数量)的消息。长轮询只是确保您不会得到虚假的空响应,即使队列中有消息,您的读取请求也不会返回任何消息。
我曾经对此进行了一些实验,并发现随着队列中消息数量的增加,响应中返回的消息数量接近于所请求的消息数量。通常,在队列中有1000多条消息时,根据我的实验,每次都能看到它返回10条消息(顺便说一下,这是读取请求可以返回的最大值)。事实上,这种行为在短轮询中也观察到了。即使有100多个消息,返回的消息数量也不总是10条,尽管其中很大一部分请求都会返回10条消息。显然,这并不是有保证的,但这是您通常会看到的情况。
我在我的博客中记录了实验结果,并在下面发布了链接,以便您查看更多实验细节。

http://pragmaticnotes.com/2017/11/20/amazon-sqs-long-polling-versus-short-polling/


@Mortiz,我已经添加了更多详细信息。你们能再次审查一下并根据需要重新投票吗? - Amitkumar Gupta

1
由于SQS在后端是一个分布式系统,所以无法保证任何特定请求都能返回正在轮询的最大消息数。您需要不断地调用,直到您有足够多的项或队列已清空为止。

那么长轮询在这种情况下并没有真正帮助。尽管它正在查看所有托管服务器上的消息,因此确实知道队列中的所有消息,但有时它可能会返回消息的子集。某些事情听起来不太对劲。 - kaputabo
1
Kaputabo,长轮询并不是为了帮助这种使用情况而设计的。事实就是如此。实际上,SQS似乎并不适合你的用例。也许你应该考虑使用DynamoDB? - tster

0

将执行超时时间设置为大于0的值。我已将执行超时时间设置为2秒,现在它正在返回队列中所有可用的9条消息。


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