Lambda マネージドインスタンスの .NET ランタイム
.NET ランタイムの場合、Lambda マネージドインスタンスは実行環境ごとに 1 つの .NET プロセスを使用します。複数の同時リクエストは、.NET タスクを使用して処理されます。
同時実行数の設定
Lambda が各実行環境に送信する同時リクエストの最大数は、関数設定の PerExecutionEnvironmentMaxConcurrency 設定で制御できます。これはオプションの設定となっており、デフォルト値はランタイムによって異なります。.NET ランタイムの場合、デフォルト値は vCPU あたり 32 件の同時リクエスト数になります。または、独自の値を設定できます。Lambda は、各実行環境の容量に応じて、設定された最大数までの同時リクエストの数を自動的に調整し、それらのリクエストを取得します。
同時実行のための関数の構築
Lambda マネージドインスタンスを使用する場合は、他の複数同時実行環境と同じ同時実行のセーフなプラクティスを適用する必要があります。ハンドラーオブジェクトはすべてのタスクで共有されるため、変更可能な状態はスレッドセーフである必要があります。これには、コレクション、データベース接続、およびリクエスト処理中に変更されるあらゆる静的オブジェクトが含まれます。
AWS SDK クライアントはスレッドセーフなため、特別な処理は必要ありません。
例: データベース接続プール
次のコードは、同時リクエスト間で共有される静的データベース接続オブジェクトを使用します。SqlConnection オブジェクトはスレッドセーフではありません。
public class DBQueryHandler { // Single connection shared across threads - NOT SAFE private SqlConnection connection; public DBQueryHandler() { connection = new SqlConnection("your-connection-string-here"); connection.Open(); } public string Handle(object input, ILambdaContext context) { using var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT ..."; // your query using var reader = cmd.ExecuteReader(); ... } }
これに対処するには、接続プールから取得したリクエストごとに個別の接続を使用します。Microsoft.Data.SqlClient などの ADO.NET プロバイダーは、接続オブジェクトが開かれると、接続プーリングを自動的にサポートします。
public class DBQueryHandler { public DBQueryHandler() { } public string Handle(object input, ILambdaContext context) { using var connection = new SqlConnection("your-connection-string-here"); connection.Open(); using var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT ..."; // your query using var reader = cmd.ExecuteReader(); ... } }
例: コレクション
標準の .NET コレクションはスレッドセーフではありません。
public class Handler { private static List<string> items = new List<string>(); private static Dictionary<string, object> cache = new Dictionary<string, object>(); public string FunctionHandler(object input, ILambdaContext context) { items.Add(context.AwsRequestId); cache["key"] = input; return "Success"; } }
同時実行がセーフになるように、System.Collections.Concurrent 名前空間のコレクションを使用します。
public class Handler { private static ConcurrentBag<string> items = new ConcurrentBag<string>(); private static ConcurrentDictionary<string, object> cache = new ConcurrentDictionary<string, object>(); public string FunctionHandler(object input, ILambdaContext context) { items.Add(context.AwsRequestId); cache["key"] = input; return "Success"; } }
共有の /tmp ディレクトリ
/tmp ディレクトリは、実行環境内のすべての同時リクエスト間で共有されます。同じファイルに同時に書き込むと、別のリクエストによってファイルが上書きされるなど、データの破損が発生する可能性があります。これに対処するには、共有ファイルのファイルロックを実装するか、リクエストごとに一意のファイル名を使用して競合を回避します。空き容量を占有しないよう、不要なファイルはクリーンアップしてください。
ログ記録
ログインターリービング (ログでインターリーブされるさまざまなリクエストからのログエントリ) は、複数同時実行システムでは正常です。Lambda マネージドインスタンスを使用する関数は常に、高度なログ記録コントロールで導入した構造化された JSON ログ形式を使用します。この形式には requestId が含まれ、ログエントリを 1 つのリクエストに関連付けることができます。context.Logger オブジェクトを使用してログを生成すると、requestId は各ログエントリに自動的に含まれます。詳細については、「.NET での Lambda の高度なログ記録コントロールの使用」を参照してください。
リクエストコンテキスト
context.AwsRequestId プロパティを使用して、現在のリクエストのリクエスト ID にアクセスします。
context.TraceId プロパティを使用して、X-Ray トレース ID にアクセスします。これにより、現在のリクエストのトレース ID への同時実行に対応したアクセスが可能になります。Lambda は、Lambda マネージドインスタンスの _X_AMZN_TRACE_ID 環境変数をサポートしていません。AWS SDK を使用すると、X-Ray トレース ID が自動的に伝播されます。
初期化とシャットダウン
関数の初期化は、実行環境ごとに 1 回行われます。初期化中に作成されたオブジェクトは、リクエスト間で共有されます。
拡張機能を持つ Lambda 関数の場合、実行環境はシャットダウン中に SIGTERM シグナルを出力します。このシグナルは拡張機能によって使用され、バッファのフラッシュなどのクリーンアップタスクをトリガーします。SIGTERM イベントにサブスクライブすることで、データベース接続を閉じるなどの関数のクリーンアップタスクを実行できます。実行環境のライフサイクルの詳細については、「Lambda 実行環境のライフサイクルの概要」を参照してください。
依存関係バージョン
Lambda マネージドインスタンスには、以下のパッケージバージョンの最小要件が必要です。
-
Amazon.Lambda.Core: バージョン 2.7.1 以降
-
Amazon.Lambda.RuntimeSupport: バージョン 1.14.1 以降
-
OpenTelemetry.Instrumentation.AWSLambda: バージョン 1.14.0 以降
-
AWSXRayRecorder.Core: バージョン 2.16.0 以降
-
AWSSDK.Core: バージョン 4.0.0.32 以降
Powertools for AWS Lambda (.NET)
Powertools for AWS Lambda (.NET) および AWS Distro for OpenTelemetry – Instrumentation for DotNet
次のステップ
-
「Lambda マネージドインスタンスのスケーリング」について説明する