如何防止连接到 Amazon VPC 的 Lambda 函数超时?

2 分钟阅读
0

我想防止我的 AWS Lambda 函数与 Amazon Virtual Private Cloud(Amazon VPC)的连接超时。

概述

在没有响应的情况下在负载均衡器或 NAT 网关后面调用 Lambda 函数 API 调用可能是由于连接空闲超时问题造成的。TCP 流的负载均衡器空闲超时值为 350 秒。

如果 API 调用响应延迟是间歇性的或小于 350 秒,这可能是由于重试和超时问题造成的。有关详细信息,请参阅如何解决在使用 AWS SDK 调用 Lambda 函数时出现的重试和超时问题?

解决方法

为防止连接中断,可以启用值小于 350 秒的 TCP keepalive 来重置空闲超时。TCP keepalive 通过每 20 秒向前端和后端连接发送数据包来防止连接处于空闲状态。

您可以在类似如下内容的套接字对象上调用 setKeepAlive

Node.js 14 和 Node.js 16

const http = require('http');

function invokeApi() {

  return new Promise(resolve => {

    var callback = function(response) {
      var str = '';

      response.on('data', function (chunk) {
        str += chunk;
      });

      response.on('end', function () {
        response = '**** ALB response: ' + str;
        resolve(response)
      });
    }

    const url = 'http://<alb-dns>';
    const myTimeout = 1000*60*15; // 15 minutes
    let req = http.get(url, callback);

    req.on('error', (e) => {
      console.error(`Got error: ${e.message}`);
    });

    req.on('socket', function (socket) {
      socket.setKeepAlive(true, 1000); //set SO_KEEPALIVE

      socket.setTimeout(myTimeout);  

      socket.on('timeout', function() {
        console.log('request is about to timeout');
        req.abort();
      });
    });
    req.end();
  })
}

exports.handler = async (event) => {
    let output = await invokeApi();
    const response = {
        statusCode: 200,
        body: output,
    };
    return response;
};

Node.js 18

import * as http from "http"

function invokeApi() {

  return new Promise(resolve => {

    var callback = function(response) {
      var str = '';

      response.on('data', function (chunk) {
        str += chunk;
      });

      response.on('end', function () {
        response = '**** ALB response: ' + str;
        resolve(response);
      });
    }

    const url = 'http://<alb-dns>';
    const myTimeout = 1000*60*15; // 15 minutes
    let req = http.get(url, callback);

    req.on('error', (e) => {
      console.error(`Got error: ${e.message}`);
    });

    req.on('socket', function (socket) {
      socket.setKeepAlive(true, 1000); //set SO_KEEPALIVE

      socket.setTimeout(myTimeout);  

      socket.on('timeout', function() {
        console.log('request is about to timeout');
        req.abort();
      });
    });
    req.end();
  })
}

export const handler = async(event) => {
    let output = await invokeApi();
    const response = {
        statusCode: 200,
        body: output,
    };
    return response;
};

Python 3.x

import json
import socket
import requests
from urllib3.connection import HTTPConnection

HTTPConnection.default_socket_options = HTTPConnection.default_socket_options + [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]
def lambda_handler(event, context):
    try:
        r = requests.get("http://<alb-dns>",timeout=(5,900))

        output = r.text
    except requests.RequestException as e:
        print(e)
        raise e
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": output,
        }),
    }

使用适用于 Java2 的 AWS SDK,您可以传递一个预配置的 HTTP 客户端,如下所示:

LambdaClient awsLambda = LambdaClient.builder()
    .region(region
    .httpClient(ApacheHttpClient.builder()
                   .tcpKeepAlive(true)
                   .connectionTimeout(Duration.ofSeconds(5))
                   .connectionMaxIdleTime(Duration.ofMinutes(15))
                   .socketTimeout(Duration.ofMinutes(15)).build())
    .build();

使用适用于 Python 的 Amazon SDK(Boto3)许您使用配置文件。创建包含以下内容的 .config 文件:

[default]
tcp_keepalive=true

然后,在目录 /var/task/config 中使用 .config 文件的值创建一个 Lambda 环境变量 AWS_CONFIG_FILE

有关详细信息,请参阅连接空闲超时


相关信息

宣布针对 AWS Lambda 函数改进了 VPC 网络

如何解决在私有 VPC 上使用 NAT 网关时出现的连接问题?

AWS 官方
AWS 官方已更新 1 年前