我在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中有解决方案吗?或者我应该更换队列吗?
答案 0 :(得分:6)
SQS不保证邮件的排序。最好以接受此代码的方式编写代码,或切换到 进行排序的队列系统(如果您绝对需要它)。
文档位于here,相关段落为:
如果我希望按顺序发送消息怎么办? Amazon SQS尽最大努力保留邮件中的订单,但由于队列的分布式特性,我们无法保证您将按照发送邮件的确切顺序接收邮件。您通常会在邮件中放置排序信息或时间戳,以便在收到邮件时重新排序。
答案 1 :(得分:1)
如果您100%需要保留邮件订单的服务,则可以使用Amazon Kinesis。
Amazon Kinesis流是有序的数据记录序列。检索数据时保留记录的顺序,并且多个应用程序可以接收记录。这与Amazon SQS队列不同,后者的消息顺序无法保证,一旦消耗,消息就会从队列中消失。
使用来自Amazon Kinesis的消息比从Amazon SQS队列中检索消息更复杂,但它可能更符合您的要求。
答案 2 :(得分:1)
创建SQS队列时,请将其标记为FIFO队列,这样可以保证消息的正确顺序。
请查看AWS文档中的Recommendations for FIFO (First-In-First-Out) Queues。
答案 3 :(得分:0)
我想有四种方法可以解决这个问题:
1)创建一个独立的计数/订购服务,以便发布者可以为每个事件标记一个计数。消费者然后还要检查带有ACID的“消费者数量”(共同更新),以确保收到的消息将得到处理,否则它将等待重试或引发“出故障”通知。
2)使事件本身真正成为REST,因此它们保存了需要正确使用的所有数据,因此现在的订购变得无关紧要。
3)创建一个“馈送”服务,该服务从长SQS队列中读取并仅在短于某个给定的低值时才馈送更短的SQS队列。然后,多个使用者从较短的队列中进食。这不能完全确保与多个使用者进行订购,但是会限制乱序处理的范围。
4)使用大量无聊的消费者,以使队列始终确实很短。这不能完全确保订购,但可以限制乱序处理的程度。
关于(1),可以将每个事件的处理分为两个单独的阶段,即处理阶段和提交阶段(处理结果得以保留),只有在第二个提交阶段才可以强制执行订购,这可能允许多个处理阶段在单独的使用者上同时运行。