AWS SQS 触发 lambda 突然停顿并且不删除消息
AWS SQS triggered lambda suddenly stalling and not deleting messages
我有一个 lambda python 函数连接到批处理大小为 1 的 SQS 队列触发器。SQS 消息包含 S3 上的文件位置以及一些元数据值。
当一条消息可用时,该函数会从消息中引用的 S3 上的文件中读取一些元数据,创建一个包含更多元数据的 YAML 文件,然后将其转储到 S3 并引用 RDS 数据库中的元数据文件。
在我将大量消息提交到队列 (~1.7k) 之后,一开始似乎一切顺利,可用消息的数量下降,而 lambda 执行量增加。
但一段时间后,执行时间显着增加到函数超时的程度(超时设置为 90 秒)。我在日志中没有看到任何错误,并且执行仍然成功(如果它们没有超时)。
这一切都可以在监控中看到:
这里在lambda监控中,可以看到持续时间突然增加,同时执行并发下降,突然出现错误(最坏情况下有两个错误,60%s的成功率)。你看到的差距是我禁用和启用希望改变的触发器。
同期SQS监控如下:
你可以看到可见的消息数稳定在 192,收到的消息数在 5。更让我困惑的是,即使执行成功,删除的消息数下降到 0。
我真的想不通为什么现在会出现这个问题,我一直在使用这个配置w/o问题和变化。
会不会是 SQS 触发器配置在从 S3 读取超时时阻塞了队列?有什么线索吗?
谢谢!
编辑:
RDS 集群指标:
如果 lambda 成功处理消息但 SQS 队列未删除任何消息,这很可能表明队列可见性超时与 lambda 超时之间不匹配。您应该确保接收消息的 lambda 服务有足够的时间来完成消息并告诉 SQS 删除消息。如果 lambda 需要 70 秒,但队列只有 60 秒的可见性超时,这意味着 lambda 服务的 DeleteMessage
请求将被静默拒绝,消息将保留在队列中并在稍后,可能会产生完全相同的结果。
首先注意:如果您为 lambda 设置了并发限制,则队列的可见性超时不仅应等于 lambda 超时,而且应等于 lambda 超时的倍数,即 lambda 超时的 5 或 6 倍。原因是 lambda 服务可能会获取消息,尝试调用 lambda,但 lambda 会限制它,然后 lambda 服务等待(lambda 超时)重试消息。在所有这些过程中,lambda 服务不会 return 将消息发送到队列,它会将消息保存在内存中,不会延长可见性超时或类似的事情。在消息实际被丢弃/returned 到 SQS 之前,它会重试几次(5 或 6 次)。您应该能够通过创建一个超时为例如的 lambda 来尝试这一点。 10 秒,让它简单地睡眠/等待 9 秒,并发限制为 1,然后将 1000 条消息放入队列。
第二个注意事项:这种突然的批量操作可能会导致各种正常情况下不会发生的节流问题,无论是您自己的其他下游服务还是 AWS 的服务。例如。如果您的 lambda 执行 assume-role
调用或从具有 500 个请求的 S3 检索一些配置对象,消息在队列中的瞬间通常会给您带来麻烦。底层数据库可能会变得缓慢/无响应缓冲所有传入请求等。
该问题的一个简单解决方案是通过设置并发限制来限制 lambda。此时请确保队列具有适当的可见性超时,如上一节所述。并确保您收到请求实际增加的警报,请确保您观察 ApproximateAgeOfOldestMessage
队列指标,以便在积压增加时收到警报。
第三个注意事项:如果 lambda 仅在大量请求进入时行为不当,一个潜在的原因是 lambda 中的内存泄漏。由于 lambda 的执行上下文在不同的调用之间重复使用,因此内存泄漏也存在于不同的调用中。如果传入的请求很少,你可能总是会得到一个新的执行上下文,这意味着 lambda 每次都从新内存开始,但是如果有很多请求传入执行上下文,那么执行上下文肯定会被重用,这可能会导致泄漏变得如此之大由于垃圾收集的启动,lambda 基本上冻结了。lambda 中的 /tmp
目录也是如此。
我有一个 lambda python 函数连接到批处理大小为 1 的 SQS 队列触发器。SQS 消息包含 S3 上的文件位置以及一些元数据值。
当一条消息可用时,该函数会从消息中引用的 S3 上的文件中读取一些元数据,创建一个包含更多元数据的 YAML 文件,然后将其转储到 S3 并引用 RDS 数据库中的元数据文件。
在我将大量消息提交到队列 (~1.7k) 之后,一开始似乎一切顺利,可用消息的数量下降,而 lambda 执行量增加。
但一段时间后,执行时间显着增加到函数超时的程度(超时设置为 90 秒)。我在日志中没有看到任何错误,并且执行仍然成功(如果它们没有超时)。
这一切都可以在监控中看到:
这里在lambda监控中,可以看到持续时间突然增加,同时执行并发下降,突然出现错误(最坏情况下有两个错误,60%s的成功率)。你看到的差距是我禁用和启用希望改变的触发器。
同期SQS监控如下:
你可以看到可见的消息数稳定在 192,收到的消息数在 5。更让我困惑的是,即使执行成功,删除的消息数下降到 0。
我真的想不通为什么现在会出现这个问题,我一直在使用这个配置w/o问题和变化。
会不会是 SQS 触发器配置在从 S3 读取超时时阻塞了队列?有什么线索吗?
谢谢!
编辑:
RDS 集群指标:
如果 lambda 成功处理消息但 SQS 队列未删除任何消息,这很可能表明队列可见性超时与 lambda 超时之间不匹配。您应该确保接收消息的 lambda 服务有足够的时间来完成消息并告诉 SQS 删除消息。如果 lambda 需要 70 秒,但队列只有 60 秒的可见性超时,这意味着 lambda 服务的 DeleteMessage
请求将被静默拒绝,消息将保留在队列中并在稍后,可能会产生完全相同的结果。
首先注意:如果您为 lambda 设置了并发限制,则队列的可见性超时不仅应等于 lambda 超时,而且应等于 lambda 超时的倍数,即 lambda 超时的 5 或 6 倍。原因是 lambda 服务可能会获取消息,尝试调用 lambda,但 lambda 会限制它,然后 lambda 服务等待(lambda 超时)重试消息。在所有这些过程中,lambda 服务不会 return 将消息发送到队列,它会将消息保存在内存中,不会延长可见性超时或类似的事情。在消息实际被丢弃/returned 到 SQS 之前,它会重试几次(5 或 6 次)。您应该能够通过创建一个超时为例如的 lambda 来尝试这一点。 10 秒,让它简单地睡眠/等待 9 秒,并发限制为 1,然后将 1000 条消息放入队列。
第二个注意事项:这种突然的批量操作可能会导致各种正常情况下不会发生的节流问题,无论是您自己的其他下游服务还是 AWS 的服务。例如。如果您的 lambda 执行 assume-role
调用或从具有 500 个请求的 S3 检索一些配置对象,消息在队列中的瞬间通常会给您带来麻烦。底层数据库可能会变得缓慢/无响应缓冲所有传入请求等。
该问题的一个简单解决方案是通过设置并发限制来限制 lambda。此时请确保队列具有适当的可见性超时,如上一节所述。并确保您收到请求实际增加的警报,请确保您观察 ApproximateAgeOfOldestMessage
队列指标,以便在积压增加时收到警报。
第三个注意事项:如果 lambda 仅在大量请求进入时行为不当,一个潜在的原因是 lambda 中的内存泄漏。由于 lambda 的执行上下文在不同的调用之间重复使用,因此内存泄漏也存在于不同的调用中。如果传入的请求很少,你可能总是会得到一个新的执行上下文,这意味着 lambda 每次都从新内存开始,但是如果有很多请求传入执行上下文,那么执行上下文肯定会被重用,这可能会导致泄漏变得如此之大由于垃圾收集的启动,lambda 基本上冻结了。lambda 中的 /tmp
目录也是如此。