如何解决在使用 AWS SDK 调用 Lambda 函数时出现的重试和超时问题?

4 分钟阅读
0

当我使用 AWS SDK 调用 AWS Lambda 函数时,该函数超时,API 请求失败或 API 操作重复。

简短描述

由于以下情况,使用 AWS 开发工具包调用 Lambda 函数时可能会出现重试和超时问题:

  • 远程 API 无法访问或需要很长时间才能响应 API 调用。
  • API 调用在套接字超时时间内没有得到响应。
  • 在 Lambda 函数的超时时间内,API 调用没有得到响应。

**注意:**出现网络连接问题时,API 调用可能需要比预期更长的时间。网络问题还可能导致重试和 API 请求重复。要为这些情况做好准备,请确保您的 Lambda 函数是幂等的。

如果您使用 AWS SDK 发起 API 调用,但调用失败,则 AWS SDK 会自动重试该调用。AWS SDK 重试的次数和重试时间由每个 AWS SDK 不同的设置决定。

默认 AWS SDK 重试设置

**注意:**其他 AWS 服务的某些值可能会有所不同。

AWS SDK最大重试次数连接超时套接字超时
Python (Boto 3)取决于服务60 秒60 秒
JavaScript/Node.js取决于服务不适用120 秒
Java310 秒50 秒
.NET4100 秒300 秒
Go3不适用不适用

要对重试和超时问题进行故障排除,请先查看 API 调用的日志以找到问题。然后,根据每个用例的需要更改 AWS SDK 的重试次数和超时设置。为了留出足够的时间响应 API 调用,请在 Lambda 函数超时设置中添加时间。

解决方法

记录 AWS SDK 发出的 API 调用

使用 Amazon CloudWatch Logs 获取有关连接失败以及每次连接尝试重试次数的详细信息。有关详细信息,请参阅将 CloudWatch Logs 日志与 Lambda 结合使用。或者,请参阅您使用的 AWS SDK 的以下说明:

API 调用建立连接失败(连接超时)的错误日志示例

START RequestId: b81e56a9-90e0-11e8-bfa8-b9f44c99e76d Version: $LATEST2018-07-26T14:32:27.393Z    b81e56a9-90e0-11e8-bfa8-b9f44c99e76d    [AWS ec2 undefined 40.29s 3 retries] describeInstances({})
2018-07-26T14:32:27.393Z    b81e56a9-90e0-11e8-bfa8-b9f44c99e76d    { TimeoutError: Socket timed out without establishing a connection

...

错误日志示例,其中 API 调用连接成功,但在 API 响应时间过长后超时(套接字超时)

START RequestId: 3c0523f4-9650-11e8-bd98-0df3c5cf9bd8 Version: $LATEST2018-08-02T12:33:18.958Z    3c0523f4-9650-11e8-bd98-0df3c5cf9bd8    [AWS ec2 undefined 30.596s 3 retries] describeInstances({})2018-08-02T12:33:18.978Z    3c0523f4-9650-11e8-bd98-0df3c5cf9bd8    { TimeoutError: Connection timed out after 30s

**注意:**如果 API 请求未在 Lambda 函数的超时时间内得到响应,则不会生成这些日志。如果 API 请求因函数超时而结束,请尝试以下方法之一:

  • 更改 SDK 中的重试设置,以便所有重试都在超时时间内完成。
  • 临时增加 Lambda 函数超时设置,以便有足够的时间生成 SDK 日志。

更改 AWS SDK 的设置

AWS SDK 的重试次数和超时设置应留出足够的时间让您的 API 调用获得响应。要确定每种设置的正确值,请测试不同的配置并获取以下信息:

  • 建立成功连接的平均时间
  • 完整 API 请求所花费的平均时间(直到成功返回)

有关更改重试次数和超时设置的详细信息,请参阅以下 AWS SDK 客户端配置文档:

以下是一些更改每个运行时的重试次数和超时设置的命令示例。

**注意:**请务必将每个设置的示例值替换为您的用例值。

用于更改重试次数和超时设置的 Python (Boto 3) 命令示例

# max_attempts: retry count / read_timeout: socket timeout / connect_timeout: new connection timeout
from botocore.session import Session
from botocore.config import Config

s = Session()
c = s.create_client('s3', config=Config(connect_timeout=5, read_timeout=60, retries={'max_attempts': 2}))

用于更改重试次数和超时设置的 JavaScript/Node.js 命令示例

// maxRetries: retry count / timeout: socket timeout / connectTimeout: new connection timeout
var AWS = require('aws-sdk');

AWS.config.update({

    maxRetries: 2,

    httpOptions: {

        timeout: 30000,

        connectTimeout: 5000

    }

});

用于更改重试次数和超时设置的 JavaScript V3 命令示例

const { S3Client, ListBucketsCommand } = require("@aws-sdk/client-s3");
const { NodeHttpHandler } = require("@aws-sdk/node-http-handler");
const client = new S3Client({
    requestHandler: new NodeHttpHandler({
        connectionTimeout: 30000,
        socketTimeout: 50000
    }),
    maxAttempts: 2
});

用于更改重试次数和超时设置的 Java 命令示例

// setMaxErrorRetry(): retry count / setSocketTimeout(): socket timeout / setConnectionTimeout(): new connection timeout
ClientConfiguration clientConfig = new ClientConfiguration();

clientConfig.setSocketTimeout(60000);
clientConfig.setConnectionTimeout(5000);
clientConfig.setMaxErrorRetry(2);

AmazonDynamoDBClient ddb = new AmazonDynamoDBClient(credentialsProvider,clientConfig);

用于更改重试次数和超时设置的 .NET 命令示例

// MaxErrorRetry: retry count / ReadWriteTimeout: socket timeout / Timeout: new connection timeout
var client = new AmazonS3Client(

    new AmazonS3Config {
        Timeout = TimeSpan.FromSeconds(5),
        ReadWriteTimeout = TimeSpan.FromSeconds(60),
        MaxErrorRetry = 2
});

用于更改重试次数设置的 Go 命令示例

// Create Session with MaxRetry configuration to be shared by multiple service clients.sess := session.Must(session.NewSession(&aws.Config{
    MaxRetries: aws.Int(3),
}))

// Create S3 service client with a specific Region.
svc := s3.New(sess, &aws.Config{
    Region: aws.String("us-west-2"),
})

用于更改请求超时设置的 Go 命令示例

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()
// SQS ReceiveMessage
params := &sqs.ReceiveMessageInput{ ... }
req, resp := s.ReceiveMessageRequest(params)
req.HTTPRequest = req.HTTPRequest.WithContext(ctx)
err := req.Send()

(可选)更改 Lambda 函数的超时设置

较低的 Lambda 函数超时会导致健康连接提前断开。增加函数超时设置,以便您的 API 调用有足够的时间获得响应。

使用以下公式估计函数超时所需的基本时间:

First attempt (connection timeout + socket timeout) + Number of retries x (connection timeout + socket timeout) + 20 seconds additional code runtime margin = Required Lambda function timeout

Lambda 函数超时计算示例

**注意:**以下计算适用于配置为三次重试、10 秒连接超时和 30 秒套接字超时的 AWS SDK。

First attempt (10 seconds + 30 seconds) + Number of retries [3 * (10 seconds + 30 seconds)] + 20 seconds additional code runtime margin = 180 seconds

相关信息

调用

了解 Lambda 中的重试行为

Lambda 配额

AWS 官方
AWS 官方已更新 5 个月前