Amazon 仮想プライベートクラウド (Amazon VPC) への AWS Lambda 関数接続がタイムアウトしないようにしたいと考えています。
簡単な説明
ロードバランサーまたは NAT ゲートウェイの背後で応答なしで Lambda 関数 API 呼び出しを呼び出すのは、接続アイドルタイムアウトの問題が原因である可能性があります。TCP フローのロードバランサーアイドルタイムアウト値は 350 秒です。
API 呼び出しの応答遅延が断続的または 350 秒未満の場合は、再試行とタイムアウトの問題が原因である可能性があります。詳細については、「 AWS SDK を使用して Lambda 関数を呼び出す際の再試行とタイムアウトの問題をトラブルシューティングするにはどうすればよいですか?」を参照してください。
解決策
接続が切断されないようにするには、350 秒未満の値で TCP キープアライブをオンにして、アイドルタイムアウトをリセットします。TCP キープアライブは、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;
};
パイソン 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,
}),
}
AWS SDK for Java2 を使用すると、次のような事前設定済みの 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();
AWS SDK for Python (Boto3) を使用すると、設定ファイルを使用できます。次の内容の .config ファイルを作成します。
[default]
tcp_keepalive=true
次に、/var/task/configディレクトリにある .config ファイルの値を使用して Lambda 環境変数 AWS\ _CONFIG\ _FILE を作成します。
詳細については、「 接続アイドルタイムアウト」を参照してください。
関連情報
AWS Lambda 関数の VPC ネットワーキングの改善に関する発表
プライベート VPC で NAT ゲートウェイを使用する際の接続問題をトラブルシューティングするにはどうすればよいですか?