LoginSignup
5
0

VPCネットワーク内での350秒のタイムアウトを確認してみた

Last updated at Posted at 2023-12-21

はじめに

この記事はOptimind Advent Calendar 2023の22日目の記事となります。

概要

最近NATゲートウェイなどを経由した(AWS Lambdaなどの)同期通信が350秒程度で通信が切断されてしまうということを知りました(詳しくは以下の記事を参考にしてください)。なので、AWS LambdaやEC2を建ててみて実際にタイムアウトするかを簡単に確認してみたいと思います。

実験

まずAWS LambdaからAWS Lambdaとの同期通信を試してみます。次に、Private Subnetの中に建てたEC2からAWS Lambdaとの同期通信をおこなってみます。

実験のための簡単なプログラムをGPT-4-sanに伺いながら作成しました。lambda1はlambda2との同期通信用のプログラムで、lambda2はsleepするだけの処理をしています。

lambda1
import json
import boto3
from botocore.config import Config

def lambda_handler(event, context):
    
    config = Config(region_name="ap-northeast-1", read_timeout=900, connect_timeout=900)
    client = boto3.client('lambda', config=config)
    function_name = 'lambda2'
    
    # Lambda関数の実行
    try:
        response = client.invoke(
            FunctionName=function_name,
            InvocationType='RequestResponse', 
            Payload=json.dumps({})
        )
        ret = response['Payload'].read()
        print (ret)
    except Exception as e:
        print (e)
        
    
    return {
        'statusCode': 200,
        'body': ret
    }

lambda2
import json
import time

def lambda_handler(event, context):
    time.sleep(360)
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

AWS Lambda(lambda1)からAWS Lambda(lambda2)を呼び出したときは以下のような結果を得ることができました。360秒のsleepでも問題なく接続できています。

b'{"statusCode": 200, "body": "\\"Hello from Lambda!\\""}'

Private Subnet内のEC2からLambdaを呼び出してみる

EC2からlambda2を呼び出すためのプログラムを作成します。

invoke_lambda.py
import json
import boto3
import time
from botocore.config import Config

conf = Config(region_name="ap-northeast-1", read_timeout=400, connect_timeout=400, retries={"mode": "standard", "total_max_attempts": 1})
client = boto3.client('lambda', config=conf)
function_name = 'lambda2'

# Lambda関数の実行
start = time.time()
try:
    response = client.invoke(
        FunctionName=function_name,
        InvocationType='RequestResponse', 
        Payload=json.dumps({})
    )
    print(response['Payload'].read())
except Exception as e:
    print (e)

print ('elapsed time: ', time.time() - start)

sleep時間が10秒のときの実行は問題なく終了しました。意図通りに実行していそうです。

[ec2-user@ip-xx~]$ python3 invoke_lambda.py 
b'{"statusCode": 200, "body": "\\"Hello from Lambda!\\""}'
elapsed time:  10.290184497833252

早速sleep時間が360秒のときを見てみます。対応するlambda2のログのREPORTを見ると360秒で終了しています。readTimeoutの設定時間は400秒にしているため、タイムアウト設定値内に終わっていそうです。

REPORT RequestId: xxx	Duration: 360002.70 ms	Billed Duration: 360003 ms	Memory Size: 128 MB	Max Memory Used: 41 MB	

しかし、EC2の方を見るとReadTimeoutという結果になりました。elapsedTimeを見てみると400秒と設定されたタイムアウトの時間まで結果を待ち続けているようで、接続の応答が来ていなさそうに見えます。

[ec2-user@ip-xx~]$ python3 invoke_lambda.py 
Read timeout on endpoint URL: "https://lambda.ap-northeast-1.amazonaws.com/xxx"
elapsed time:  400.1450889110565

一応どのタイミングでReadTimeoutになるのかを確認してみました。

  • 345秒のsleep
[ec2-user@ip-xx~]$ python3 invoke_lambda.py 
b'{"statusCode": 200, "body": "\\"Hello from Lambda!\\""}'
elapsed time:  345.31132411956787
  • 349秒のsleep
[ec2-user@ip-xx~]$python3 invoke_lambda.py 
b'{"statusCode": 200, "body": "\\"Hello from Lambda!\\""}'
elapsed time:  349.288724899292
  • 350秒のsleep
[ec2-user@ip-xx~]$ python3 invoke_lambda.py 
Read timeout on endpoint URL: "https://lambda.ap-northeast-1.amazonaws.com/xxx"
elapsed time:  400.09561228752136

349秒で成功しますが350秒だとだめみたいでタイムアウトの設定値まで待っており、挙動が一致していそうです。

紹介されている方法を試してみる

紹介されているとおりにTCPキープアライブの動作を設定するためのパラメータの変更と、アプリケーション側でのTCPキープアライブを有効化してみます。詳しい説明は以下の文献を参考にしてください。

初期値は以下の通りでした。

[ec2-user@ip-xx~]$ cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
[ec2-user@ip-xx~]$ cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
[ec2-user@ip-xx~]$ cat /proc/sys/net/ipv4/tcp_keepalive_probes
9

350秒で通信が切断しないように設定値を以下のように変更します。

[ec2-user@ip-xx~]$ sudo sysctl -w net.ipv4.tcp_keepalive_time=45
net.ipv4.tcp_keepalive_time = 45
[ec2-user@ip-xx~]$ sudo sysctl -w net.ipv4.tcp_keepalive_intvl=45
net.ipv4.tcp_keepalive_intvl = 45
[ec2-user@ip-xx~]$ sudo sysctl -w net.ipv4.tcp_keepalive_probes=9
net.ipv4.tcp_keepalive_probes = 9

次に、~/.aws/configに以下の設定を書き込みます。

[default]
tcp_keepalive=true

無事通信が成功しました!

[ec2-user@ip-xx~]$ python3 invoke_lambda.py 
b'{"statusCode": 200, "body": "\\"Hello from Lambda!\\""}'
elapsed time:  360.0784122943878

おわりに

最近の(?)AWSのアップデートでECS on Fargateでカーネルパラメータを調整できるようになったみたいなのでこちらもまた試してみたいと思います。

参考

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0