pko*_*out 2 amazon-sqs serverless
我正在使用无服务器框架来使用来自 SQS 的消息。发送到队列的一些消息不会被消耗。他们直接进入飞行中的 SQS 状态,然后从那里进入我的死信队列。当我查看消费者日志时,我可以看到它消费并成功处理了 9/10 消息。一个总是不会被消耗并最终进入死信队列。我设置reservedConcurrency为 1,以便一次只有一个消费者可以运行。函数消费者timeout设置为 30 秒。这是消费者代码:
module.exports.mySQSConsumer = async (event, context) => {
context.callbackWaitsForEmptyEventLoop = false;
console.log(event.Records);
await new Promise((res, rej) => {
setTimeout(() => {
res();
}, 100);
});
console.log('DONE');
return true;
}
Run Code Online (Sandbox Code Playgroud)
消费者功能配置如下:
functions:
mySQSConsumer:
handler: handler.mySQSConsumer
timeout: 30 # seconds
reservedConcurrency: 1
events:
- sqs:
arn: arn:aws:sqs:us-east-1:xyz:my-test-queue
batchSize: 1
enabled: true
Run Code Online (Sandbox Code Playgroud)
如果我删除该await功能,它将处理所有消息。如果我将超时增加到 200 毫秒,更多的消息将直接进入运行中状态,并从那里进入死信队列。这段代码非常简单。知道为什么它会跳过一些消息吗?使用第一条语句时,未使用的消息甚至不会显示在日志中console.log()。他们似乎完全被忽视了。
我解决了这个问题。SQS队列Lambda函数事件触发的工作方式与我想象的不同。消息被推送到 Lambda 函数中,而不是由它拉取。我认为 AWS 可以对此进行更好的设计,但事实就是如此。
问题是设置Default Visibility Timeout为 30 秒以及Reserved Concurrency设置为 1。当 SQS 队列很快被数千条记录填满时,AWS 开始以比单个函数更快的速度将消息推送到 Lambda 函数。实例可以处理它们。AWS“假设”它可以简单地启动更多 Lambda 实例来跟上背压。但是,并发限制不允许它启动更多实例 - Lambda 函数受到限制。因此,该函数开始向 AWS 后端返回某些消息的失败,从而将失败的消息隐藏 30 秒(默认设置),并在此期限后将它们放回队列中进行重新处理。由于单个实例需要处理的记录太多,30秒后,Lambda函数仍然很忙,无法再次处理这些消息。于是,这种情况又重演了,消息又恢复为不可见状态,持续 30 秒。这总共重复 3 次。第三次尝试后,消息将进入死信队列(我们以这种方式配置了 SQS 队列)。
为了解决这个问题,我们将时间增加到Default Visibility Timeout5 分钟。这足够 Lambda 函数处理队列中的大部分消息,而失败的消息则在不可见的状态下等待。5 分钟后,它们被推回到队列中,并且由于 Lambda 函数不再繁忙,因此它将处理其中的大部分。其中一些必须经过两次隐身才能被成功处理。
因此,解决此问题的方法是像Default Invisibility Timeout我们一样增加或增加消息进入死信队列之前所需的失败次数。
我希望这可以帮助别人。
| 归档时间: |
|
| 查看次数: |
1084 次 |
| 最近记录: |