AWS LambdaのNode.jsランタイムでTCP接続を使いまわそう!(AWS_NODEJS_CONNECTION_REUSE_ENABLED)
Node.js のHTTP/HTTPS エージェントはデフォルトで keepalive
が無効化されているため、新しいリクエストがあるたびに新しい TCP 接続を作成します。
AWS Lambda の Node.js ランタイムを利用している場合、環境変数で AWS_NODEJS_CONNECTION_REUSE_ENABLED=1
を設定することでkeepalive
が有効になり、TCP 接続を再利用してより効率的に通信するようになります。
この動作を確認してみます。
背景
Node.js のHTTP/HTTPS エージェントはデフォルトで keepalive
が無効化されています。
keepAlive Keep sockets around even when there are no outstanding requests, so they can be used for future requests without having to reestablish a TCP connection... Default: false.
https://nodejs.org/api/http.html#http_new_agent_options
DynamoDB クエリなどの短期間のオペレーションでは、TCP 接続を設定する際のレイテンシーのオーバーヘッドが、オペレーション自体よりも大きくなる可能性があります。さらに、DynamoDB の保管時の暗号化は AWS KMS と統合されているため、データベースからのレイテンシーが発生する可能性があります。データベースはオペレーションごとに新しい AWS KMS キャッシュエントリを再確立する必要があります。
軽微なHTTP/HTTPS通信を高頻度で行っている場合、keepalive
を有効にすることでスループットの向上を期待できます。
keepalive を有効化するには?
TCP接続の keepalive
を有効にするには2種類の方法があります。
AWS LambdaのNode.jsランタイム
実行環境が AWS Lambda の Node.js ランタイムの場合、環境変数で AWS_NODEJS_CONNECTION_REUSE_ENABLED=1
を設定するだけです。
このオプションは AWS SDK for JavaScript のバージョン 2.463.0 以降で対応しています。
Node.js全般
Node.jsのHTTP/HTTPSクライアントに対して汎用的に使える方法です。
HTTP/HTTPS エージェントの keepAlive
プロパティを true
にします。
AWS SDKの場合は、以下の通りです。(ソースコードは公式ドキュメントから)
const AWS = require('aws-sdk'); // http or https const http = require('http'); const agent = new http.Agent({ keepAlive: true }); AWS.config.update({ httpOptions: { agent } });
計測してみる
AWS Lambda から DynamoDB に接続し、 keepalive
の効果を計測します。
DynamoDB に Get-Item
する Lambda 関数を用意し、 DynamoDB の操作に要した時間を計測します。
// based on https://theburningmonk.com/2019/02/lambda-optimization-tip-enable-http-keep-alive/ const AWS = require('aws-sdk') const ddb = new AWS.DynamoDB.DocumentClient(); exports.handler = async (event) => { const start = new Date().getTime() await ddb.get({TableName:'test', Key:{'id':1}}).promise() const end = new Date().getTime() console.log(`Log:${end-start}`) const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
この関数を keepalive 設定の 有・無それぞれのケースで100回シーケンシャルに同期呼び出ししました。
計測結果
DynamoDB の処理時間
HTTPS 接続を伴う DynamoDB の操作に限定すると、keepalive を有効にすることで多くのケースで10倍近く速くなりました。
keepalive | p50 | p90 | p95 |
---|---|---|---|
false | 42 | 62 | 73 |
true | 5 | 27 | 64 |
※単位はミリ秒
遅い5%を除いてヒストグラムにしてみましょう。
keepalive を有効にすると、安定して劇的に速く処理できていることがわかります。
keepalive 無効
keepalive 有効
Lambda の応答時間
AWS X-Ray で Lambda 関数の応答時間の分布を確認しましょう。(responsetime <= 0.1
に限定)
DynamoDB の処理時間の違いが Lambda 関数の応答時間にも大きく影響していることがわかります。
keepalive 無効
keepalive 有効
まとめ
TCP の keepalive
を有効にすると、接続を再利用することで、接続コストの軽減を期待できます。
Node.jsのHTTP/HTTPSエージェントはkeepalive接続がデフォルトで無効になっているため、設定を見直しましょう。
AWS環境でNode.js LambdaからDynamoDBと高頻度で通信しているような場合は keepalive の有効を試してみる価値が大いにあります。
Lambda関数の環境変数でAWS_NODEJS_CONNECTION_REUSE_ENABLED=1
と設定するけで、ソースコードを変更せずに keepalive
を有効にできます。