收到的SQS消息无序

时间:2016-10-31 10:39:30

标签: amazon-web-services amazon-sqs

我在python中使用boto3客户端。 我将消息推送到sqs但是以错误的顺序接收它们。 我可以看出他们的发送时间是正确的。

队列的创建方式如下:

boto_session = boto3.Session(region_name=..,aws_access_key_id=..,                                      aws_secret_access_key=...)
sqs_client = boto_session.resource('sqs', endpoint_url=endpoint_url)
sqs_client.create_queue(QueueName=...)

推送消息的代码:

boto_session = boto3.Session(region_name=..,aws_access_key_id=..,aws_secret_access_key=...)
sqs_client = boto_session.resource('sqs', endpoint_url=endpoint_url)
queue = sqs_client.get_queue_by_name(QueueName=stream_name)

i = 0
while i < 10:
    print 'b ' + str(i)
    queue.send_message(MessageBody=raw_data.push(json.dumps(dict(id=i)))
    sleep(2)
    i += 1

用于轮询消息的代码:

sqs_resource = boto_session.resource('sqs', endpoint_url=endpoint_url)
queue = sqs_resource.get_queue_by_name(QueueName=queue_name)

while True:
   messages = queue.receive_messages(MaxNumberOfMessages=1,VisibilityTimeout=10,WaitTimeSeconds=5)
   for m in messages:
         print  m.data
         queue.delete_messages(
                Entries=[
                    {
                        'Id': m.message_id,
                        'ReceiptHandle': m.receipt_handle
                    }
                ]
            )

我运行了创建队列代码,然后我推送了消息,然后运行了一个进程来使用消息,如图所示。

我清楚地看到这些消息是随机排列的。

在sqs中有解决方案吗?或者我应该更换队列吗?

4 个答案:

答案 0 :(得分:6)

SQS不保证邮件的排序。最好以接受此代码的方式编写代码,或切换到 进行排序的队列系统(如果您绝对需要它)。

文档位于here,相关段落为:

  

如果我希望按顺序发送消息怎么办?   Amazon SQS尽最大努力保留邮件中的订单,但由于队列的分布式特性,我们无法保证您将按照发送邮件的确切顺序接收邮件。您通常会在邮件中放置排序信息或时间戳,以便在收到邮件时重新排序。

答案 1 :(得分:1)

如果您100%需要保留邮件订单的服务,则可以使用Amazon Kinesis

Amazon Kinesis流是有序的数据记录序列。检索数据时保留记录的顺序,并且多个应用程序可以接收记录。这与Amazon SQS队列不同,后者的消息顺序无法保证,一旦消耗,消息就会从队列中消失。

使用来自Amazon Kinesis的消息比从Amazon SQS队列中检索消息更复杂,但它可能更符合您的要求。

请参阅:Amazon Kinesis Streams Key Concepts

答案 2 :(得分:1)

创建SQS队列时,请将其标记为FIFO队列,这样可以保证消息的正确顺序。

请查看AWS文档中的Recommendations for FIFO (First-In-First-Out) Queues

答案 3 :(得分:0)

我想有四种方法可以解决这个问题:

1)创建一个独立的计数/订购服务,以便发布者可以为每个事件标记一个计数。消费者然后还要检查带有ACID的“消费者数量”(共同更新),以确保收到的消息将得到处理,否则它将等待重试或引发“出故障”通知。

2)使事件本身真正成为REST,因此它们保存了需要正确使用的所有数据,因此现在的订购变得无关紧要。

3)创建一个“馈送”服务,该服务从长SQS队列中读取并仅在短于某个给定的低值时才馈送更短的SQS队列。然后,多个使用者从较短的队列中进食。这不能完全确保与多个使用者进行订购,但是会限制乱序处理的范围。

4)使用大量无聊的消费者,以使队列始终确实很短。这不能完全确保订购,但可以限制乱序处理的程度。

关于(1),可以将每个事件的处理分为两个单独的阶段,即处理阶段和提交阶段(处理结果得以保留),只有在第二个提交阶段才可以强制执行订购,这可能允许多个处理阶段在单独的使用者上同时运行。