AWS Certified Developer - Associate (DVA-C02) #2 Domain 1-1 AWS サービスでの開発 — Lambda の深掘り
#1 試験の紹介 で、DVA-C02 の重心はサーバーレスであり、その中心の中心は Lambda だと述べました。開発ドメインが 32% で最も大きく、Lambda はその中で最も頻繁に登場するサービスです。試験は Lambda を「関数を置く場所」ではなく 「どんなイベントがどのように関数を呼び出し、失敗したらどこへ行き、同時実行はどう制御されるのか」 という挙動の問題として問います。
この記事は Lambda の基本概念 (ランタイム・ハンドラー) はすばやく通り過ぎ、呼び出しタイプ・同時実行・失敗処理 のような、試験で正解を分ける箇所に時間を使います。
3 つの呼び出しタイプ #
Lambda を理解する最も重要な枠組みは 誰が、どのように呼び出すか です。呼び出しタイプによってリトライ動作と失敗処理が完全に変わるので、試験はこの区別を繰り返し問います。
| 呼び出しタイプ | 代表的なトリガー | リトライ | 失敗処理 |
|---|---|---|---|
| 同期 (Synchronous) | API Gateway, ALB, Invoke 直接呼び出し | なし (呼び出し側が処理) | 呼び出し側にエラーを返す |
| 非同期 (Asynchronous) | S3, SNS, EventBridge | 自動 2 回 (合計 3 回) | DLQ または Destination |
| ストリームポーリング (Poll-based) | SQS, Kinesis, DynamoDB Streams | 有効期限/成功まで繰り返し | バッチ失敗処理、DLQ |
同期呼び出し #
呼び出し側が応答を待ちます。API Gateway が Lambda を呼び出してその結果をクライアントに返す場合が代表的です。Lambda がエラーをスローすると リトライせず に呼び出し側へそのまま伝えられます。リトライするかどうかは呼び出し側 (例: API Gateway, SDK) が決めます。
非同期呼び出し #
呼び出し側はイベントを Lambda の内部キューに入れて即座に返ってきます。S3 がオブジェクト作成イベントで Lambda を呼んだり、SNS がメッセージを配信したりする場合です。関数が失敗すると Lambda が 自動的にあと 2 回リトライ し (遅延を置いて)、それでも失敗すると DLQ (Dead Letter Queue) または Destination に送ります。
ストリームポーリング (イベントソースマッピング) #
SQS・Kinesis・DynamoDB Streams は Lambda を直接呼び出しません。代わりに Lambda サービスが イベントソースマッピング (Event Source Mapping) でソースをポーリングしてバッチを取得したあと、関数を呼び出します。SQS 標準キューは自動的にポーリングされ、処理に失敗したメッセージは可視性タイムアウト後に再びキューに戻り、maxReceiveCount を超えると DLQ に移動します。
試験の落とし穴: SQS の DLQ はキュー自体の設定 です。非同期呼び出しの DLQ は Lambda 関数の設定 です。2 つは場所が異なります。
同時実行 (Concurrency) #
同時実行は 同じ瞬間に実行中の関数インスタンスの数 です。アカウント・リージョンごとにデフォルトの同時実行上限 (通常 1000) があり、これを関数たちが共有します。試験は同時実行制御の 2 つのオプションをよく問います。
| オプション | 目的 | 動作 |
|---|---|---|
| 予約同時実行 (Reserved Concurrency) | 特定の関数に同時実行を 確保/制限 | その関数だけが使える分を取り分けておく。他の関数の暴走から保護し、同時にその関数の上限にもなる |
| プロビジョニング済み同時実行 (Provisioned Concurrency) | コールドスタートの排除 | あらかじめ初期化された実行環境を温かく保つ。レイテンシに敏感なワークロード向け |
核心となる区別はこれです。予約同時実行は「数量の保証/制限」 であり、プロビジョニング済み同時実行は「あらかじめ温めておくこと」 です。「コールドスタートで最初の応答が遅い」という問題の答えは、予約同時実行ではなく プロビジョニング済み同時実行 です。
関数が同時実行の上限を超えると、Lambda は追加の呼び出しを スロットリング します。同期呼び出しでは 429 TooManyRequestsException が呼び出し側に返され、非同期呼び出しではリトライキューに入って後で再試行されます。
コールドスタート #
新しい実行環境が初めて作られるとき、コードのダウンロードとランタイムの初期化にかかる追加の遅延が コールドスタート です。減らす方法は決まっています。
- プロビジョニング済み同時実行 — 環境をあらかじめ初期化して温かく保つ。
- パッケージサイズの縮小・ハンドラー外での初期化 — DB 接続、SDK クライアントはハンドラーの 外 で一度だけ作って再利用。
- VPC 接続の最小化 — 過去はボトルネックでしたが Hyperplane ENI の導入で大きく改善されました。それでも不要な VPC 接続は避けます。
ハンドラー外で初期化したオブジェクトは、同じ実行環境が再利用されている間 (warm) は保持されます。DB コネクションをハンドラーの中で毎回新しく開くコードはアンチパターンです。
環境変数とレイヤー #
- 環境変数 — 設定値をコードと分離して注入します。デフォルトで保存時に暗号化され、機密性の高い値は KMS カスタマーマネージドキーで暗号化するか、Parameter Store・Secrets Manager からランタイムに読み込みます。環境変数に平文のパスワードを入れる答案は不正解です。
- レイヤー (Layer) — 共通ライブラリ・依存関係を分離して複数の関数で共有します。デプロイパッケージを小さく保ち、依存関係を一箇所で管理できます。1 つの関数に最大 5 つまで付与でき、展開後の合計 250MB の上限に含まれます。
バージョンとエイリアス #
Lambda はコードを公開すると 不変のバージョン (version) が作られ、エイリアス (alias) で特定のバージョンを指します。エイリアスは デプロイ戦略 で重み付けベースのカナリアデプロイの中心になるので、ここでは「エイリアスがバージョンを指すポインタ」という点だけ押さえておきます。
失敗処理 — DLQ と Destination #
非同期呼び出しですべてのリトライが失敗したら、イベントが消えないように保管する必要があります。
| 方式 | 成功/失敗の区別 | 対象 |
|---|---|---|
| DLQ | 失敗のみ | SQS キューまたは SNS トピック |
| Lambda Destination | 成功・失敗の両方 | SQS, SNS, EventBridge, 別の Lambda |
Destination がより新しく推奨される方式 です。成功・失敗の両方をルーティングでき、失敗イベントにエラーのコンテキストがより豊富に含まれます。DLQ は失敗イベントだけを保管します。
冪等性 (Idempotency) #
非同期・ストリームベースの呼び出しは 同じイベントが 2 回以上配信されうる (at-least-once) です。SQS 標準キュー、非同期リトライがいずれも重複を生みうるので、関数は 同じ入力で何度実行されても結果が同じになるよう に設計する必要があります。
- 冪等性キー (注文 ID など) を DynamoDB に条件付き書き込みで記録して重複処理を防ぎます。
- 決済・在庫の減算のように副作用がある作業ほど冪等性の設計が必須です。
このテーマは #6 SDK 開発パターン でさらに扱います。
試験の出題パターン #
- 「API Gateway が呼び出した Lambda が失敗したら自動リトライされるか?」 → 同期呼び出しなので Lambda の自動リトライなし。呼び出し側が処理。
- 「S3 イベントで呼び出された Lambda が失敗した。イベントを失わないためには?」 → 非同期呼び出しなので DLQ/Destination を設定。
- 「関数の最初の応答が遅い (コールドスタート)。解決策は?」 → プロビジョニング済み同時実行。
- 「特定の関数がアカウント全体の同時実行を食いつぶして他の関数がスロットリングされる。」 → 予約同時実行で隔離。
- 「DB コネクションを呼び出しごとに新しく開く。」 → ハンドラー外で初期化して再利用。
- 「SQS が同じメッセージを 2 回配信した。」 → 冪等性の設計 (標準キューは at-least-once)。
よく出会う落とし穴 #
1) 非同期のリトライ回数を同期に適用する #
自動 2 回リトライは 非同期呼び出し の動作です。同期呼び出しは Lambda がリトライしません。
2) 予約同時実行とプロビジョニング済み同時実行を混同する #
予約は数量の確保/制限、プロビジョニングはコールドスタートの排除です。「レイテンシに敏感」ならプロビジョニングです。
3) DLQ の場所を混同する #
SQS トリガーの DLQ はキューの設定、非同期 Lambda の DLQ は関数の設定です。
4) 環境変数にシークレットを平文で保存する #
機密情報は Secrets Manager/Parameter Store から読むか、KMS で暗号化します。
まとめ #
この記事の要点:
- 呼び出しタイプ — 同期 (リトライなし)・非同期 (自動 2 回 + DLQ/Destination)・ストリームポーリング (イベントソースマッピング)
- 同時実行 — 予約 (数量の確保/制限) と プロビジョニング (コールドスタートの排除) は目的が異なる
- コールドスタート — プロビジョニング済み同時実行、ハンドラー外の初期化の再利用で緩和
- 環境変数は設定の分離、レイヤー は共通依存関係の共有
- 失敗処理 — Destination (成功・失敗の両方) が DLQ (失敗のみ) より推奨
- at-least-once 配信なので 冪等性 の設計が必須
次へ — Domain 1-2 API Gateway #
Lambda がバックエンドロジックなら、その前で HTTP リクエストを受けてルーティングする関門が API Gateway です。#3 API Gateway では、REST API と HTTP API の違い、Lambda プロキシ統合、認証 (IAM・Cognito・Lambda オーソライザー)、スロットリングと使用量プラン、キャッシング、そしてステージとデプロイまで見ていきます。