AWS Serverless本番運用Vol1|Lambda×APIGW×Step Functions

目次

Serverless本番運用入門 Vol1 — Lambda × API Gateway × Step Functions

fig01: Serverless 3本柱 全体アーキテクチャ (Lambda / API Gateway / Step Functions 選定マトリクス)

AWS本番運用 第12軸 Serverless本番運用 シリーズ起点 Vol1
本記事は AWS本番運用 全11軸 (IAM/EKS/復旧/AI/セキュリティ/コスト/マルチアカウント/Observability/Network/DevOps/Database) を完遂した中堅エンジニアに向けた、第12軸 = Serverless本番運用 の起点記事です。Lambda × API Gateway × Step Functions の3本柱 (Compute / API / Workflow) を全11軸統合視点で再統合し、本番品質の Serverless 運用パターンを確立します。

前11軸シリーズ (23記事)

  • IAM Vol1-4 / EKS Vol1-3 / 復旧 Vol1-4 / AI Vol1-2 / セキュリティ Vol1-2 / コスト Vol1 / マルチアカウント Vol1 / Observability Vol1 / Network Vol1-2 / DevOps Vol1-2 / Database Vol1

関連シリーズ (Serverless 個別 deep-dive)

  • Lambda deep-dive: Container Image / Powertools+Layers / SnapStart / Authorizer (4本)
  • Step Functions deep-dive: Express vs Standard / Distributed Map / Callback Pattern / Error handling / SDK Direct Integration / IO Filters / DataFlow / ECS Job連携 (10本以上)
  • API Gateway deep-dive: Lambda Authorizer Production

1. なぜServerless本番運用か — 全11軸からの架橋 + 第12軸結節点

IAM・EKS・復旧・AI・セキュリティ・コスト・マルチアカウント・Observability・Network・DevOps・Database の全11軸 23記事を完遂した読者は、次の問いに直面する。「アプリケーションロジックをどう実行し、API として公開し、複雑なワークフローを安全に完走させるか」。インフラは整った。しかし Serverless 領域の本番品質運用を体系化していないと、Cold Start 遅延・VPC 制約・API 設計ミス・Step Functions ステート爆発などのペインが蓄積していく。本 Vol1 は第12軸 Serverless本番運用シリーズの起点として、Lambda × API Gateway × Step Functions の3本柱を全11軸統合視点で再統合し、本番品質の Serverless 運用パターンを確立する。

全11軸完遂後の「次の壁」

全11軸を完遂した中堅エンジニアが Serverless 設計に踏み込むとき、Application 層だけでは解決できない5つの壁が立ちはだかる。

壁1: Compute層の選定と Cold Start 管理

Lambda は起動コスト (Cold Start) が p99 レイテンシに直撃する。init フェーズのコンテナ初期化・ランタイム起動・ハンドラロードの3段階を正しく理解しないまま Provisioned Concurrency を設定すると、コストが数十倍に膨れ上がる。Container Image 形式と ZIP デプロイでは Cold Start 特性が異なり、SnapStart (Java/Python/.NET) の適用条件も限定的だ。3本柱のうち最も運用パラメータが多いのが Lambda であり、Memory/Timeout/Ephemeral Storage/VPC attachment の組み合わせが本番品質を左右する。

壁2: VPC ENI 枯渇事故

Lambda を VPC 内に配置すると、同時実行数の増加に比例して ENI (Elastic Network Interface) を消費する。ENI の作成には数十秒かかることがあり、急激なスパイク時に ENI プールが枯渇すると Lambda 起動自体が失敗する。EKS × Lambda 混在環境や、Database Vol1 で導入した RDS/Aurora への接続を Lambda から行う構成では、RDS Proxy の導入が必須になる。VPC 設計 (Network Vol1-2) の知識と Serverless の接続管理が統合されて初めて安全な本番運用が成立する。

壁3: API Gateway スロットリングと認証設計

API Gateway はデフォルトで リージョン単位のスロットリング上限 (10,000 RPS) と アカウント単位の上限 が存在する。HTTP API と REST API の選択を誤ると、後から必要な機能 (Usage Plan / Lambda Authorizer / API Key 管理) が利用できなくなる。Cognito Authorizer・Lambda Authorizer・IAM 認証の3方式を適切に選択しないと認証バイパスのリスクが残る。

壁4: Step Functions ステート爆発

Step Functions のステートマシン定義 (ASL: Amazon States Language) は、複雑な分岐・並列処理・エラーハンドリングを加えると状態数が爆発的に増える。Standard Workflow と Express Workflow の選択基準を誤ると、実行履歴の保持期限切れ・コスト超過・デバッグ困難が発生する。Distributed Map (10万件並列処理) や Callback Pattern (外部サービス待機) の本番運用は、既存の Step Functions 実践編 deep-dive が詳細を扱っており、本 Vol1 ではその統合視点を提供する。

壁5: IAM Role 設計の複雑化

Serverless 構成では Lambda 実行ロール・API Gateway ロール・Step Functions 実行ロール・EventBridge ルールロールと、サービスごとに IAM Role が増殖する。IAM Vol1-4 で習得した最小権限設計・SCP・Permission Boundary の原則を Serverless 文脈に適用する設計パターンが必要だ。特に Lambda から DynamoDB/RDS/Secrets Manager へのアクセスは、リソースベースポリシーと実行ロールの両面から制御する。

本 Vol1 で得られる4つの成果

  1. 3本柱選定フレームワーク — Compute (Lambda) / API (API Gateway) / Workflow (Step Functions) の役割分担と選定マトリクス。実行時間・同時実行数・Stateful度・コストの4軸で最適解を導く手順。

  2. Lambda 本番運用 — Cold Start 対策 (Provisioned Concurrency / SnapStart / Container Image 最適化)・VPC ENI 管理・RDS Proxy 連携・Lambda Insights によるオブザーバビリティ。実 SAM/Terraform テンプレートで再現可能な本番品質設定を提供する。

  3. API Gateway 本番運用 — HTTP API vs REST API 選定・Cognito/Lambda/IAM 認証3方式・スロットリング設計・カスタムドメイン設定・Usage Plan 管理。API Gateway × Lambda の統合パターンを IaC で完全定義する。

  4. Step Functions 本番運用 — Standard/Express 選定・Distributed Map 本番運用・Callback Pattern・エラーハンドリング設計。既存 deep-dive 資産 (10本以上) への橋渡しと、本番品質マシン定義のテンプレートを提供する。

既存 deep-dive シリーズとの住み分け

本 Vol1 は 統合俯瞰ハブ記事 として位置付ける。Lambda / Step Functions / API Gateway の各 deep-dive シリーズは引き続き「個別深掘りの素材」として尊重する。

カテゴリ既存 deep-dive (個別深掘り)本 Vol1 の役割
LambdaContainer Image / Powertools+Layers / SnapStart / Authorizer (4本)Cold start × VPC × PC の統合本番設定
Step FunctionsExpress vs Standard / Distributed Map / Callback / Error / SDK直接統合 / IO Filters / DataFlow (10本以上)Standard/Express選定 + 本番品質起点
API GatewayLambda Authorizer ProductionHTTP vs REST × 認証3方式統合

既存の deep-dive 記事を読んだ読者は、本 Vol1 で「全体がどうつながるか」を把握できる。本 Vol1 を読んだ読者は、各 deep-dive 記事で「特定技術を深く掘り下げる」ことができる。

痛点5選: Serverless 本番運用の地雷

痛点1: Cold Start での p99 遅延急増

Lambda 関数がトラフィックスパイク後にスケールアウトすると、新規コンテナの init フェーズが p99 レイテンシを急増させる。Provisioned Concurrency を設定しても Application Auto Scaling で適切にスケジュール設定しないと、朝9時のトラフィック増加時に未準備のコンテナが Cold Start を引き起こす。SnapStart は Java 環境では有効だが、Lambda 関数のコード変更のたびに Snapshot 作成が走り、デプロイ時間が増加する副作用がある。

痛点2: VPC ENI 枯渇事故

RDS Aurora への接続のために Lambda を VPC 内に配置したところ、同時実行数が 500 を超えた時点で ENI 作成待ちによる ResourceNotReadyException が多発した事例がある。対策は RDS Proxy の導入 (コネクションプーリング)、および Lambda Subnet に十分な IP アドレス空間を確保すること。/24 サブネット (254 IP) では容量不足になるケースがあり、/20 以上の割り当てが推奨される。

痛点3: API Gateway スロットリング設定漏れ

デフォルトの API Gateway は Usage Plan 未設定の状態で本番公開すると、スクレイピングや過負荷アクセスパターンでアカウント全体のスロットリング上限に達し、他の API も巻き込んでレート制限される。HTTP API と REST API では Usage Plan の設定方法が異なり、HTTP API には Usage Plan が存在しない (Lambda 関数側でレート制御が必要)。

痛点4: Step Functions ステート数上限

Standard Workflow は実行あたり最大 25,000 状態遷移の上限がある。大規模な Distributed Map (S3 CSV 100万行処理等) でネストが深くなると、状態遷移数の上限超過で実行が失敗する。対策は Express Workflow への切り替えまたは処理単位の分割。ただし Express Workflow には実行履歴の保持期限 (90日) とイベント数上限があり、監査要件がある場合は CloudWatch Logs との連携設計が必要になる。

痛点5: Lambda × RDS 接続数枯渇

Lambda のコンカレンシーが増加すると各コンテナが独立して DB コネクションを確立するため、RDS/Aurora の接続数上限 (max_connections) を瞬時に超過する。RDS Proxy を経由することでコネクションプーリングが機能するが、RDS Proxy 自体にも同時接続数の上限 (インスタンスクラス依存) があるため、負荷試験で確認が必要だ。Database Vol1 で設計した RDS/Aurora 構成と本 Vol1 の Lambda 接続設計は密接に連動する。

対象読者と前提スキル

本 Vol1 の対象読者は、AWS 本番運用の全11軸 (IAM/EKS/復旧/AI/セキュリティ/コスト/マルチアカウント/Observability/Network/DevOps/Database) を一通り経験し、Serverless 本番運用を体系的に整理したい中堅エンジニアだ。

前提スキル:
– Lambda 関数の基本的なデプロイ・実行経験
– API Gateway での REST API または HTTP API 作成経験
– Step Functions の基本ステートマシン作成経験 (あれば望ましい)
– SAM または Terraform での IaC 経験
– IAM Role / ポリシー設計の基礎知識 (IAM Vol1-4 相当)

Serverless 本番運用 5原則

全11軸の経験を経て Serverless に取り組む際、以下の5原則を設計の基軸にすることで痛点の多くを事前に防げる。

  1. ステートレス設計の徹底 — Lambda 関数は呼び出しをまたいで状態を持たない前提で設計する。状態が必要なら DynamoDB・ElastiCache・Step Functions に委ねる。/tmp の再利用は許容するが依存してはならない。

  2. コンカレンシー予算の明示 — Lambda のデフォルト同時実行上限 (アカウント 1,000) は全関数で共有される。本番 API に Reserved Concurrency を設定し、重要でない関数がコンカレンシーを枯渇させないよう予算配分する。

  3. べき等性の保証 — SQS トリガーの Lambda は at-least-once で呼ばれる。同一イベントを2回処理しても副作用が出ない設計 (DynamoDB 条件付き書き込み・冪等キー管理) が必須だ。

  4. タイムアウト連鎖の設計 — API Gateway (29秒) → Lambda (設定値) → RDS Proxy (接続タイムアウト) の3層それぞれにタイムアウトが存在する。上流のタイムアウトが下流より短いと、処理が続いているのに上流がエラー返却するという不整合が生まれる。

  5. オブザーバビリティファースト — Lambda Insights・X-Ray・Structured Logging (AWS Lambda Powertools) を最初から有効化する。Cold Start 頻度・p99 レイテンシ・エラー率の3指標を CloudWatch Dashboard で常時監視する体制を最初から整える。

本記事の各セクション構成

§タイトル主要内容
§1なぜServerless本番運用か全11軸からの架橋・痛点5選・住み分け
§2AWS Serverless 3本柱整理 + サービスマップ3本柱定義・選定マトリクス・統合アーキテクチャ
§3Lambda 本番運用 ★山場1Cold Start × VPC × Provisioned Concurrency × Lambda Insights
§4API Gateway 本番運用 ★山場2HTTP vs REST × 認証3方式 × スロットリング × カスタムドメイン
§5Step Functions 本番運用 ★山場3Standard/Express選定 × Distributed Map × Callback × エラー設計
§63本柱統合設計パターンAPI GW → Lambda → Step Functions 実践IaC
§7詰まり7選 + 演習5問実際の障害事例と解決パターン・理解確認問題
§8全11軸+第12軸 クロスリンク関連記事ナビ
AWS本番運用 全11軸 + 第12軸 Serverless 記事ナビ (24記事)


2. AWS Serverless 3本柱整理 + サービスマップ

AWS Serverless の全体像を把握するには、まず3本柱の役割分担を明確にする必要がある。Lambda・API Gateway・Step Functions はそれぞれ独立したサービスだが、実際の本番システムでは3つが連携して動作する。3本柱のどれが欠けても本番品質の Serverless アーキテクチャは成立しない。このセクションでは3本柱の定義・AWSサービス全体マップ・選定マトリクス・統合アーキテクチャパターンを整理する。

3本柱の定義

Compute (Lambda)

Lambda は AWS の FaaS (Function as a Service) であり、Serverless アーキテクチャの中心的な Compute 層だ。イベント駆動で実行され、サーバーのプロビジョニング・管理が不要なのが特徴。実行環境 (Execution Environment) は使い回され、コールド/ウォームスタートの概念を理解することが本番運用の鍵になる。Lambda が担うのは「ビジネスロジックの実行」であり、変換・検索・集計・外部API呼び出しなどのステートレスな処理に最適だ。

主要な機能:
Function URL: HTTP エンドポイントを Lambda に直接割り当て。API Gateway を経由しない軽量な API 公開
Container Image: 最大 10GB のコンテナイメージでデプロイ。依存ライブラリが大きいML推論や複雑な処理に対応
Lambda Layer: 共通ライブラリ・設定をレイヤーとして管理。複数関数間で再利用可能
SnapStart: Java/Python/.NET の init フェーズを事前に Snapshot 化して Cold Start を削減
Provisioned Concurrency: 指定した数の実行環境を事前ウォームアップし、Cold Start を排除

API (API Gateway)

API Gateway は API 公開・認証・スロットリング・バージョン管理を担う Managed API 層だ。Lambda のトリガーとして最も一般的に使われ、HTTP リクエストを Lambda に変換して返す。REST API・HTTP API・WebSocket API の3種類があり、用途に応じた選択が重要だ。

主要な機能:
HTTP API: 低レイテンシ・低コストの API エンドポイント。JWT/Lambda 認証対応。Usage Plan 非対応
REST API: 完全な機能セット。Usage Plan / API Key / Request Validation / Response Mapping 対応
WebSocket API: 双方向リアルタイム通信。チャット・通知・ゲームに活用
Custom Authorizer (Lambda Authorizer): リクエストの認証・認可をカスタム Lambda 関数で実装
Usage Plan + API Key: クライアント別のスロットリング・クォータ管理
Throttling: Burst Limit と Rate Limit でスパイクアクセスから Lambda を保護

Workflow (Step Functions)

Step Functions はステートマシンとしてのワークフロー管理層だ。複数の Lambda 関数・AWS サービス呼び出しを ASL (Amazon States Language) で定義し、処理の順序・分岐・並列・エラーハンドリング・リトライを可視化して管理する。Lambda だけでは実現困難な「長時間処理」「複雑な分岐」「ヒューマンアプルーバル待機」を安全に実装できる。

主要な機能:
Standard Workflow: 最大 1 年間の実行。完全な実行履歴・監査対応。高コスト
Express Workflow: 最大 5 分の実行。高スループット向け。実行履歴は CloudWatch Logs
Distributed Map: S3 / JSON 配列を並列処理。最大 10,000 並列。大規模バッチに活用
Callback Pattern: .waitForTaskToken で外部サービス (承認フロー / SQS / SNS) の応答待機
SDK直接統合: Lambda を介さず AWS サービス (DynamoDB / S3 / ECS 等) を直接呼び出し

AWS Serverless サービスマップ

3本柱を中心に、周辺サービスを含めたマップを整理する。

カテゴリ1: Compute (Lambda 中心)

サービス/機能説明本番での主用途
AWS LambdaFaaS 本体ビジネスロジック実行
Lambda Function URLLambda への直接 HTTP エンドポイント軽量 Webhook / 内部 API
Lambda Container Imageコンテナ形式デプロイ (最大 10GB)ML 推論・大規模依存
Lambda Layer共通ライブラリ管理Powertools / SDK 共通化
Lambda SnapStartJava/Python init Snapshot 化Cold Start 削減
Provisioned Concurrency実行環境事前ウォームアップSLA 要件付き API
Lambda InsightsCloudWatch による Lambda 監視p99/エラー率/メモリ監視

カテゴリ2: API (API Gateway 中心)

サービス/機能説明本番での主用途
HTTP API低コスト API エンドポイント内部API / モバイルバックエンド
REST APIフル機能 API エンドポイント外部公開 / 課金管理あり
WebSocket API双方向リアルタイム通信チャット / 通知
Lambda Authorizerカスタム認証 LambdaJWT / OAuth 独自検証
Cognito AuthorizerCognito User Pool 認証ユーザー認証済み API
Usage Plan + API Keyクライアント別スロットリングB2B API 課金管理
Custom Domain独自ドメイン設定本番公開 URL

カテゴリ3: Workflow (Step Functions 中心)

サービス/機能説明本番での主用途
Standard Workflow長時間・監査対応ワークフロー注文処理 / 承認フロー
Express Workflow高スループット短時間ワークフローストリーミング処理
Distributed Map大規模並列処理 (S3 / 配列)ETL / バッチ処理
Callback Pattern外部応答待機ヒューマンアプルーバル / SQS 連携
SDK Direct IntegrationAWS サービス直接呼び出しDynamoDB / ECS 直接操作

カテゴリ4: Glue層 (統合サービス)

サービス/機能説明本番での主用途
EventBridgeイベントルーティング / スケジューラーLambda トリガー / サービス間連携
SQSメッセージキューLambda 非同期トリガー / デカップリング
SNSPub/Sub 通知ファンアウト / アラート配信
Kinesis Data Streamsリアルタイムストリーミングログ処理 / リアルタイム分析
SAM (Serverless Application Model)Serverless IaC フレームワークLambda/API GW/Step Functions 定義
CDK (Cloud Development Kit)TypeScript/Python でインフラ定義大規模 Serverless 構成管理

選定マトリクス: 4軸7パターン

実行時間・同時実行数・Stateful度・コストの4軸でサービス組み合わせを選定する。

パターン実行時間同時実行Statefulコスト推奨構成
同期 API~29秒中 (〜1000)NoHTTP API + Lambda
外部公開 API~29秒中〜高NoREST API + Lambda + Usage Plan
リアルタイム持続NoWebSocket API + Lambda
短時間バッチ~5分YesExpress + Lambda
長時間ワークフロー~1年低〜中YesStandard + Lambda + SDK直接
大規模並列~5分×並列超高No中〜高Distributed Map + Lambda
イベント連携~15分NoEventBridge + Lambda

5ステップ判断フロー

Step1: 実行時間が 29秒を超えるか?
  Yes → Lambda + Step Functions (Standard or Express)
  No  → API Gateway + Lambda を検討

Step2: 同時実行数が 10,000 RPS を超えるか?
  Yes → HTTP API (低コスト) + Lambda Provisioned Concurrency
  No  → REST API + Usage Plan

Step3: Stateful な処理 (複数ステップ・承認待機) が必要か?
  Yes → Step Functions (Standard: 監査あり / Express: 高スループット)
  No  → Lambda 単体 or Async invoke

Step4: 大規模データ並列処理 (10万件以上) が必要か?
  Yes → Step Functions Distributed Map
  No  → Lambda + SQS (並列度は Lambda コンカレンシーで制御)

Step5: コスト重視か、機能重視か?
  コスト → HTTP API + Lambda (最安)
  機能  → REST API + Lambda (Usage Plan / Request Validation あり)

3本柱統合アーキテクチャパターン

パターン1: 同期 API + 軽量処理

Client
  │
  ▼
API Gateway (HTTP API)
  │ JWT / Cognito 認証
  ▼
Lambda (ビジネスロジック)
  │
  ▼
DynamoDB / RDS Proxy → Aurora

HTTP API で低コスト・低レイテンシ。Lambda は同期実行 (最大 29秒)。DynamoDB (ミリ秒応答) または RDS Proxy 経由 Aurora (コネクション管理)。

パターン2: 非同期ワークフロー + Step Functions

Client
  │
  ▼
API Gateway (REST API)
  │ Lambda Authorizer 認証
  ▼
Lambda (受付 + SQS 投入)
  │
  ▼
SQS → Lambda (Step Functions 起動)
  │
  ▼
Step Functions (Standard Workflow)
  ├─ Lambda (Step 1: データ検証)
  ├─ Lambda (Step 2: 外部API連携)
  ├─ Callback (承認待機)
  └─ Lambda (Step 3: 結果永続化)
 │
 ▼
DynamoDB / S3

REST API + Lambda Authorizer で認証。SQS でデカップリング。Step Functions Standard で監査可能なワークフロー管理。

パターン3: 大規模バッチ処理

EventBridge Scheduler (定期実行)
  │
  ▼
Lambda (ジョブ開始 + S3 一覧取得)
  │
  ▼
Step Functions (Distributed Map)
  │ 並列 10,000 ワーカー
  ▼
Lambda (各ファイル処理)
  │
  ▼
S3 (処理結果) / DynamoDB (集計データ)

EventBridge Scheduler で定期起動。Distributed Map で S3 の CSV / JSON ファイルを並列処理。Express Workflow で高スループット + コスト最適化。

よくある誤り3選

誤り1: HTTP API と REST API の選択ミス

HTTP API を選んだ後、Usage Plan が必要になった・Request Validation が必要になった・WAF 統合が必要になった、などの理由で REST API への移行が発生するケースが多い。選択基準: B2B API / 外部公開 / 課金管理が必要なら REST API 一択。内部 API / モバイルバックエンド / コスト優先なら HTTP API。

誤り2: Standard Workflow と Express Workflow の取り違え

Standard を選んだ後に実行頻度が増えてコストが爆発するケースと、Express を選んだ後に 90日後の監査要件で実行履歴が消えているケースが頻発する。選択基準: 監査・実行履歴保持が必要 → Standard。高頻度・短時間・コスト優先 → Express。

誤り3: Lambda Authorizer のキャッシュ設定漏れ

Lambda Authorizer はデフォルトでキャッシュ TTL = 300秒だが、設定を 0 にすると全リクエストで Authorizer Lambda が呼び出され、コストとレイテンシが増大する。本番では TTL を適切に設定し、AuthorizerResultTtlInSeconds を確認する。

3本柱性能・コスト比較表

項目LambdaAPI Gateway (HTTP)API Gateway (REST)Step Functions (Standard)Step Functions (Express)
Cold Startあり (数ms〜数秒)なしなしなしなし
最大実行時間15分29秒 (統合)29秒 (統合)1年5分
同時実行上限アカウント 1,000 (デフォルト)10,000 RPS (リージョン)10,000 RPS (リージョン)制限なし (実行数課金)制限なし
コストモデルGB-秒 + リクエスト数$1/100万リクエスト$3.5/100万リクエスト$0.025/1,000状態遷移$0.00001/状態遷移
実行履歴保持CloudWatch LogsCloudWatch LogsCloudWatch Logs90日間CloudWatch Logs のみ
監査対応Logs のみAccess LogAccess Log + X-Ray完全な実行履歴Logs 設定必須

§2まとめ — 3本柱選定チェックリスト

  • [ ] Lambda: Memory/Timeout/VPC attachment を本番要件に合わせて設定済み
  • [ ] API Gateway: HTTP API vs REST API の選択基準を確認済み
  • [ ] API Gateway: 認証方式 (Cognito / Lambda Authorizer / IAM) を決定済み
  • [ ] Step Functions: Standard vs Express の選択基準を確認済み
  • [ ] Glue層: EventBridge / SQS / SNS のトリガー設計を確認済み
  • [ ] 統合パターン: 3本柱の接続フロー (同期/非同期/バッチ) を設計済み

次の §3 では Lambda 本番運用の詳細 — Cold Start 対策・VPC 設計・Provisioned Concurrency・Lambda Insights — を実装レベルで解説する。


3. Lambda 本番運用 ★山場1 — Cold Start × VPC × Provisioned Concurrency × Lambda Insights

3-1. Lambda 関数設定 — Memory / Timeout / Ephemeral Storage

Lambda 関数のコア設定は3つある。Memory (128MB〜10,240MB)Timeout (1秒〜15分)Ephemeral Storage (512MB〜10GB) だ。Memory と Timeout はコストとパフォーマンスに直結する重要パラメータであり、デフォルト値のままで本番投入するのは危険だ。

Memory 設定

Lambda の Memory は CPU 能力とも連動している。1,769MB で vCPU 1 コアに相当し、それ以上のメモリを設定すると複数の vCPU が割り当てられる。データ変換・画像処理・機械学習推論など CPU 集約的なワークロードでは、1,769MB 以上を設定することで CPU ボトルネックを解消できる。メモリを増やすことでコストが上がるように思えるが、処理時間の短縮で相殺されるケースが多く、Lambda Power Tuning で最適点を定量的に特定することが推奨される。

Timeout 設定

Timeout のデフォルトは 3 秒だが、外部 API 呼び出しや DB 処理がある関数には短すぎる場合がある。API Gateway 統合の最大タイムアウトは 29 秒 であり、Lambda の Timeout を 29 秒超に設定しても API Gateway 側でタイムアウトする。非同期呼び出し (SQS / EventBridge) では 15 分まで設定可能だ。

Ephemeral Storage (/ tmp)

/tmp ディレクトリのデフォルト容量は 512MB だが、最大 10GB まで拡張できる。大きなファイルを一時的に展開する処理 (機械学習モデルの読み込み等) では適切に設定する。/tmp は実行環境 (Execution Environment) に紐付いており、同じ実行環境が再利用された際に前回の呼び出しからのファイルが残存することがある。

設定項目デフォルト最大値注意点
Memory128 MB10,240 MBCPUと連動。1,769MB = vCPU 1コア
Timeout3 秒15 分API GW統合は29秒上限
Ephemeral Storage512 MB10 GB/tmp 残存注意

3-2. Cold Start 構造 (Init phase / Invoke phase / Provisioned Concurrency の挙動)

Lambda のコールドスタートは、新しい実行環境 (Execution Environment) を初期化する際に発生する。コールドスタートには2つのフェーズがある。Init phase (実行環境の初期化) と Invoke phase (ハンドラーの実行) だ。

Lambda Invoke ライフサイクル シーケンス

sequenceDiagram
 participant Req as リクエスト
 participant LambdaSvc as Lambda Service
 participant EE as Execution Environment
 participant Code as 関数コード

 Note over Req,Code: Cold Start (新規EE作成時)
 Req->>LambdaSvc: Invoke
 LambdaSvc->>EE: Init phase 開始 (EE 初期化)
 EE->>EE: OS/ランタイム起動 (数十ms〜数秒)
 EE->>Code: 関数コードのダウンロード&解凍
 Code->>Code: グローバルスコープ初期化 (import/DB接続等)
 Note over EE,Code: VPC 接続時は Hyperplane ENI 割り当てもここで発生
 EE->>Code: Invoke phase 開始 (ハンドラー実行)
 Code->>Req: レスポンス返却

 Note over Req,Code: Warm Start (既存EE再利用時)
 Req->>LambdaSvc: Invoke
 LambdaSvc->>EE: Invoke phase のみ
 EE->>Code: ハンドラー直接実行 (Init phase スキップ)
 Code->>Req: レスポンス返却 (低レイテンシ)

 Note over Req,Code: Provisioned Concurrency (常時ウォームアップ)
 LambdaSvc->>EE: 事前に Init phase 完了済み
 Req->>LambdaSvc: Invoke
 LambdaSvc->>EE: Invoke phase のみ (コールドスタートなし)
 Code->>Req: レスポンス返却 (安定した低レイテンシ)

Init phase では (1) OS/ランタイムの起動、(2) 関数パッケージのダウンロードと展開、(3) グローバルスコープのコード実行 (import / DB 接続初期化 / 設定読み込み) の3段階が発生する。グローバルスコープの初期化時間が長いほどコールドスタートのレイテンシが増大するため、不要な初期化をハンドラー内に移動することで改善できる。

3-3. Cold Start 対策3パターン

fig02: Lambda Cold Start vs Provisioned Concurrency フロー

パターン1: Provisioned Concurrency

最も確実な対策。指定した同時実行数の実行環境を常時初期化済み状態で維持する。Application Auto Scaling と組み合わせてリクエストパターンに合わせた自動スケーリングも可能だ。コストは Provisioned Concurrency の設定数に比例して発生するため、Traffic pattern に合わせたスケジュール設定が重要になる。

resource "aws_lambda_provisioned_concurrency_config" "main" {
  function_name = aws_lambda_function.main.function_name
  qualifier  = aws_lambda_alias.main.name
  provisioned_concurrent_executions  = 5
}

resource "aws_appautoscaling_target" "lambda_pc" {
  max_capacity = 50
  min_capacity = 5
  resource_id  = "function:${aws_lambda_function.main.function_name}:${aws_lambda_alias.main.name}"
  scalable_dimension = "lambda:function:ProvisionedConcurrency"
  service_namespace  = "lambda"
}

パターン2: SnapStart (Java / Python / .NET)

SnapStart は Init phase 完了後のスナップショットを保存し、以降のコールドスタートでスナップショットから復元することで Init time を大幅短縮する機能だ。Java 11 以降 / Python 3.12 / .NET 8 で利用可能。Provisioned Concurrency とは異なり常時課金が発生しない点がコスト優位性だ。SnapStart の詳細実装は Lambda SnapStart 本番運用 deep-dive 記事を参照。

パターン3: Container Image 最適化

Lambda Container Image を使用する場合、イメージサイズが大きいと Init phase のダウンロード時間が増加する。マルチステージビルドと .dockerignore でイメージを最小化し、コールドスタートを短縮できる。Container Image の詳細は Lambda Container Image 本番運用 deep-dive 記事を参照。

3-4. VPC 接続 — ENI 管理 / Subnet 設計 / Security Group

Lambda を VPC 内リソース (RDS / ElastiCache / MSK 等) に接続する場合、VPC 設定が必要となる。2019 年以降、AWS は Hyperplane ENI (Elastic Network Interface) を使った共有 ENI モデルに移行し、以前の問題だった ENI 割り当て遅延と枯渇リスクが大幅に改善された。

Hyperplane ENI 共有モデル

Hyperplane ENI は同じ VPC + Subnet + Security Group 組み合わせで複数の Lambda 実行環境が ENI を共有する仕組みだ。VPC アカウントレベルで ENI 上限 (デフォルト 5,000) は引き続き存在するため、高同時実行の Lambda 関数は設計段階で ENI 使用量を見積もる必要がある。

Subnet 設計

Lambda を Multi-AZ 設計にするには、複数 AZ の Private Subnet を指定する必要がある。Lambda は指定された Subnet のうち利用可能なものにランダムに配置されるため、最低 2 AZ 以上を指定することが推奨される。Lambda は Internet Gateway に直接アクセスできないため、外部 API 呼び出しには NAT Gateway が必要だ。

Security Group 設計

Lambda 用 Security Group は Inbound ルールを空にし、Outbound のみを必要なポートに絞る。RDS への接続は RDS の Security Group で Lambda の Security Group ID を Inbound ソースとして許可する「Security Group 参照」方式が推奨される。

resource "aws_security_group" "lambda" {
  name= "lambda-production"
  vpc_id = var.vpc_id

  egress {
 from_port= 0
 to_port  = 0
 protocol = "-1"
 cidr_blocks = ["0.0.0.0/0"]
  }

  tags = { Name = "lambda-production" }
}

3-5. IAM Role 最小特権

Function Execution Role

Lambda 関数には必ず専用の IAM Execution Role を割り当てる。複数の関数間での Role 共有は避け、各関数に必要最小限の権限のみを付与する。基本として AWSLambdaBasicExecutionRole (CloudWatch Logs 書き込み) または VPC 接続時は AWSLambdaVPCAccessExecutionRole を Managed Policy として付与する。

Resource Policy (Function Policy)

Lambda Resource Policy を使うと、API Gateway や EventBridge など別のサービスから Lambda を呼び出す許可を関数単位で管理できる。Terraform では aws_lambda_permission で明示的に定義する必要がある。

resource "aws_iam_role" "lambda_exec" {
  name = "lambda-execution-role"
  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })
}

resource "aws_iam_role_policy_attachment" "vpc_access" {
  role = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}

resource "aws_lambda_permission" "api_gateway" {
  statement_id  = "AllowAPIGateway"
  action  = "lambda:InvokeFunction"
  function_name = aws_lambda_function.main.function_name
  principal  = "apigateway.amazonaws.com"
  source_arn = "${aws_apigatewayv2_api.main.execution_arn}/*/*"
}

3-6. Memory Tuning + Lambda Insights

Lambda Power Tuning

Lambda のコスト × パフォーマンス最適化には AWS Lambda Power Tuning (Step Functions ベースの OSS ツール) が有効だ。指定した Memory 設定の組み合わせ (128MB〜10,240MB) で実関数を複数回実行し、各設定のコストと実行時間をグラフ化してくれる。「コスト最小」「速度最大」「バランス」の3つの最適化軸で推奨値を提示するため、定量的な根拠をもとに Memory を設定できる。

Lambda Insights

Lambda Insights は CloudWatch Lambda Insights Extension を Lambda Layer として追加するだけで、CPU / Memory / Network / Disk I/O のメトリクスを自動収集する。通常の CloudWatch Metrics では取得できないメモリ使用率やイニシャライズ時間の分布を可視化できる。コールドスタートの頻度と init_duration (Init phase 所要時間) の分布を CloudWatch Alarm で監視することで、コールドスタート起因の遅延を早期検知できる。

3-7. Terraform 例: Lambda 本番構成

resource "aws_lambda_function" "main" {
  function_name = "myapp-production"
  role = aws_iam_role.lambda_exec.arn
  handler = "index.handler"
  runtime = "python3.12"
  timeout = 29
  memory_size= 512

  filename= data.archive_file.lambda.output_path
  source_code_hash = data.archive_file.lambda.output_base64sha256

  vpc_config {
 subnet_ids= var.private_subnet_ids
 security_group_ids = [aws_security_group.lambda.id]
  }

  environment {
 variables = {
DB_SECRET_ARN = aws_secretsmanager_secret.db.arn
ENVIRONMENT= "production"
 }
  }

  layers = [
 aws_lambda_layer_version.powertools.arn,
  ]

  ephemeral_storage {
 size = 512
  }

  tracing_config {
 mode = "Active"
  }

  tags = { Environment = "production" }
}

resource "aws_lambda_alias" "main" {
  name = "production"
  function_name = aws_lambda_function.main.function_name
  function_version = aws_lambda_function.main.version
}

resource "aws_lambda_provisioned_concurrency_config" "production" {
  function_name = aws_lambda_function.main.function_name
  qualifier  = aws_lambda_alias.main.name
  provisioned_concurrent_executions  = 5
}

deep-dive 記事クロスリンク

Lambda 関連のより深い実装パターンは以下の deep-dive 記事を参照:

【失敗事例】Cold Start p99 遅延事故 — VPC ENI 初期化で 8 秒超過

VPC 接続 Lambda のコールドスタート時に ENI 初期化が発生し、p99 レイテンシが 8 秒超に跳ね上がった遅延事故が多発する。API Gateway の統合タイムアウト上限は 29 秒であるため、8 秒超のコールドスタートに通常のハンドラー処理時間が加算されると 29 秒制限に接触するリスクが生じる。

  • 発生条件: VPC 接続 + コールドスタート頻発 (夜間バッチ後のウォームアップ切れ / 急激なトラフィック増加)
  • 対策1: Provisioned Concurrency を設定してコールドスタートを排除。スケジュールベースの Auto Scaling で夜間縮退・昼間スケールアウトを自動化
  • 対策2: Lambda Insights の init_duration メトリクスを CloudWatch Alarm で監視し、Init time 急増を早期検知
  • 対策3: グローバルスコープのコードを最小化する (import の遅延評価化 / DB 接続プールサイズ削減)
【失敗事例】VPC ENI 枯渇 — Hyperplane 未対応設計で関数起動失敗

古い設計パターン (2019年以前の推奨) に基づいて構築された Lambda 環境で、同時実行数の急増時に ENI 枯渇が発生し、関数が起動できない障害が報告されている。Hyperplane ENI モデルへの移行後もアカウントレベルの ENI 上限 (デフォルト 5,000) は存在するため、大規模並列実行では設計段階での見積もりが不可欠だ。

  • 発生条件: Lambda Reserved Concurrency を高く設定 + 複数関数が異なる Subnet/SG 組み合わせを多数使用 + アカウント ENI 上限に接近
  • 対策1: VPC 設計で Lambda 専用 Subnet (/24 以上) を確保し、他リソースとの ENI 競合を避ける
  • 対策2: CloudWatch メトリクス NetworkInterfaceCount を監視し、ENI 使用量がアカウント上限の 80% を超えたらアラームを発報する
  • 対策3: Service Quotas で ENI 上限引き上げを申請し、急激なトラフィック成長に備える

4. API Gateway 本番運用 ★山場2 — HTTP API vs REST × 認証3方式 × Throttling × CORS × Custom Domain

4-1. HTTP API vs REST API — 選定軸と本番判断基準

API Gateway は HTTP APIREST API の 2 つのエンドポイントタイプを提供する。機能セット・コスト・レイテンシが大きく異なるため、ワークロードに応じて正確に選定する必要がある。

比較軸HTTP APIREST API
コスト$1.00/100万リクエスト$3.50/100万リクエスト (アジア太平洋)
レイテンシ低い (約 30% 高速)やや高い
認証方式JWT / Lambda Authorizer / IAM AuthCognito / Lambda Authorizer / IAM / API Key
Custom Authorizer Cacheありあり (より細かい TTL 制御)
Usage Plan / API Keyなしあり (マルチテナント Throttle 管理)
Canary Deploymentありあり
Stage Variablesなしあり
Request Validationなしあり (リクエストボディ/パラメータ)
Private APIなしあり (VPC Endpoint 経由)
AWS X-Ray Tracingありあり
Access Loggingありあり

選定の原則:
HTTP API を選ぶ場合: シンプルな REST 用途・低コスト重視・JWT ベースの認証で十分・SPA / モバイルバックエンド
REST API を選ぶ場合: マルチテナント Usage Plan 管理が必要・Request Validation が必要・既存の Stage Variables を活用・Private API が必要

4-2. HTTP API 認証3方式

JWT 認証 (推奨: SPA × モバイル)

HTTP API の JWT Authorizer は、Amazon Cognito・Auth0・Okta 等の JWT を発行する IdP と直接統合できる。API Gateway が JWT の署名検証 (JWKS エンドポイント経由) と claims 検証を行うため、Lambda Authorizer が不要でコストとレイテンシが削減される。

resource "aws_apigatewayv2_api" "http_api" {
  name = "prod-http-api"
  protocol_type = "HTTP"

  cors_configuration {
 allow_origins  = ["https://app.example.com"]
 allow_methods  = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
 allow_headers  = ["Content-Type", "Authorization"]
 max_age  = 300
  }
}

resource "aws_apigatewayv2_authorizer" "jwt" {
  api_id  = aws_apigatewayv2_api.http_api.id
  authorizer_type  = "JWT"
  identity_sources = ["$request.header.Authorization"]
  name = "cognito-jwt"

  jwt_configuration {
 audience = [aws_cognito_user_pool_client.app.id]
 issuer= "https://cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.main.id}"
  }
}

resource "aws_apigatewayv2_route" "api_route" {
  api_id = aws_apigatewayv2_api.http_api.id
  route_key = "GET /items"
  authorization_type = "JWT"
  authorizer_id= aws_apigatewayv2_authorizer.jwt.id
  target = "integrations/${aws_apigatewayv2_integration.lambda.id}"
}

Lambda Authorizer (カスタム認証ロジック)

JWT 以外の認証スキーム (独自トークン・APIキー・mTLS) や、DB 照合・外部 IdP コール等の複雑なロジックが必要な場合に使用する。HTTP API の Lambda Authorizer は REQUEST type のみをサポートし、レスポンスとして シンプルな isAuthorized boolean を返すモードと IAM ポリシー を返すモードが選択できる。

IAM Auth (サービス間通信)

AWS サービス間 (他 Lambda・ECS タスク・EventBridge Pipes 等) での API 呼び出しには IAM Auth が最適だ。Signature Version 4 で署名したリクエストを API Gateway が検証する。追加の Authorizer Lambda が不要でレイテンシが最小化される。

4-3. REST API 認証設計 — Cognito / Lambda Authorizer / IAM / API Key + Usage Plan

Cognito User Pool Authorizer

REST API では Cognito User Pool をネイティブに Authorizer として設定できる。Cognito が発行した Access Token または ID Token を Authorization ヘッダで受け取り、API Gateway が署名検証と有効期限確認を行う。

API Key + Usage Plan — マルチテナント Throttle 管理

REST API 固有の機能として、テナント単位の API Key + Usage Plan による Throttle 管理がある。Account-level 制限 (10,000 rps) とは独立したテナント別 Rate/Burst 制限を設定でき、特定テナントの大量リクエストが他テナントに影響しない多テナント設計の基盤となる。

resource "aws_api_gateway_rest_api" "rest_api" {
  name = "prod-rest-api"

  endpoint_configuration {
 types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_usage_plan" "tenant_standard" {
  name = "tenant-standard"

  throttle_settings {
 rate_limit  = 100
 burst_limit = 200
  }

  quota_settings {
 limit  = 50000
 period = "DAY"
  }

  api_stages {
 api_id = aws_api_gateway_rest_api.rest_api.id
 stage  = aws_api_gateway_stage.prod.stage_name

 throttle {
path  = "/items/GET"
rate_limit  = 50
burst_limit = 100
 }
  }
}

resource "aws_api_gateway_api_key" "tenant_key" {
  name = "tenant-a-key"
}

resource "aws_api_gateway_usage_plan_key" "tenant_plan_key" {
  key_id  = aws_api_gateway_api_key.tenant_key.id
  key_type= "API_KEY"
  usage_plan_id = aws_api_gateway_usage_plan.tenant_standard.id
}

4-4. Custom Authorizer 設計 — TOKEN vs REQUEST / Cache TTL

REST API の Lambda Authorizer には TOKEN typeREQUEST type の 2 種類がある。

項目TOKEN typeREQUEST type
入力Authorization ヘッダの値のみヘッダ / クエリパラメータ / パス / ステージ変数すべて
用途Bearer Token / JWT 検証複数パラメータ組み合わせによる認証
Cache KeyToken 値指定したパラメータ組み合わせ

Cache TTL の設計指針

Lambda Authorizer の応答キャッシュは TTL 0〜3600 秒の範囲で設定できる。TTL を長くするとオーソライザー Lambda の呼び出し回数が減りコストとレイテンシが削減されるが、トークン失効後もキャッシュが有効な間はアクセスが許可される。セキュリティ要件に合わせて TTL を設計する。

resource "aws_api_gateway_authorizer" "lambda_auth" {
  name  = "custom-authorizer"
  rest_api_id = aws_api_gateway_rest_api.rest_api.id
  authorizer_uri = aws_lambda_function.authorizer.invoke_arn
  authorizer_credentials  = aws_iam_role.authorizer_invocation.arn
  type  = "TOKEN"
  identity_source= "method.request.header.Authorization"
  authorizer_result_ttl_in_seconds = 300
}

Lambda Authorizer の実装パターンについては API Gateway Lambda Authorizer Production 完全ガイド で詳しく解説している。

4-5. Throttling — Account-level / Stage-level / Method-level / Usage Plan

Throttling の階層構造

API Gateway の Throttling は 4 つの階層で制御される。上位の制限が下位の設定より優先される。

階層対象デフォルト変更方法
Account-levelアカウント全体10,000 rps / 5,000 burstサービスクォータ申請
Stage-levelStage 単位Account-level を共有Terraform aws_api_gateway_stage
Method-levelRoute + Method 単位Stage-level を共有Terraform aws_api_gateway_method_settings
Usage PlanAPI Key 単位独立設定Terraform aws_api_gateway_usage_plan

Rate vs Burst の違い

  • Rate limit: 秒間の持続スループット上限。長期的なリクエスト流量を制限する
  • Burst limit: Token Bucket アルゴリズムによる短期スパイク許容量。瞬間的なアクセス集中を吸収する
resource "aws_api_gateway_stage" "prod" {
  rest_api_id= aws_api_gateway_rest_api.rest_api.id
  stage_name = "prod"
  deployment_id = aws_api_gateway_deployment.main.id

  default_route_settings {
 throttling_rate_limit  = 1000
 throttling_burst_limit = 2000
  }
}

resource "aws_api_gateway_method_settings" "per_method" {
  rest_api_id = aws_api_gateway_rest_api.rest_api.id
  stage_name  = aws_api_gateway_stage.prod.stage_name
  method_path = "items/GET"

  settings {
 throttling_rate_limit  = 500
 throttling_burst_limit = 1000
 logging_level = "INFO"
 data_trace_enabled  = false
 metrics_enabled  = true
  }
}

4-6. CORS 設定 + Custom Domain

CORS Preflight の仕組み

ブラウザが cross-origin リクエストを送る前に OPTIONS メソッドの Preflight リクエストを API Gateway に送信する。API Gateway が適切な Access-Control-Allow-* レスポンスヘッダを返さないと、ブラウザがメインリクエストをブロックする。

HTTP API は cors_configuration ブロックで CORS を一括設定できるが、REST API では各リソースに OPTIONS メソッドを個別に定義し、Integration Response でヘッダを設定する必要がある。

Custom Domain — Edge-optimized / Regional

タイプCDN 利用推奨用途
Edge-optimizedCloudFront (自動)グローバルアクセス分散
Regionalなし (同一リージョン)Single-Region・VPC 内アクセス
PrivateVPC Endpoint のみ内部 API
resource "aws_api_gateway_domain_name" "custom" {
  domain_name  = "api.example.com"
  regional_certificate_arn = aws_acm_certificate.api.arn

  endpoint_configuration {
 types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_base_path_mapping" "v1" {
  api_id= aws_api_gateway_rest_api.rest_api.id
  stage_name  = aws_api_gateway_stage.prod.stage_name
  domain_name = aws_api_gateway_domain_name.custom.domain_name
  base_path= "v1"
}

fig03: API Gateway 認証3方式フロー + Throttling 階層

事故事例: Usage Plan 未設定で Account-level Throttle に抵触し全テナント被害
あるマルチテナント SaaS で API Gateway REST API に Usage Plan を設定していなかった場合、特定テナントが 1 万 rps を超えるリクエストを送信した際に Account-level Throttle (10,000 rps) に抵触し、同一アカウントの他テナント向け API も全て 429 Too Many Requests を返し始めた。1 テナントの大量リクエストが全テナントのサービス停止を引き起こす事態となった。

根本原因: テナントごとの API Key + Usage Plan が未設定で、全テナントが同一 Account-level 制限を共有していた。
対策: テナント単位で API Key + Usage Plan を発行し、Rate/Burst を個別設定する。各テナントの Usage Plan の Rate 合計が Account-level 制限の 80% を超えないよう設計し、余剰をバッファとして確保する。CloudWatch メトリクス 4XXError および Count をテナント別に分解し、特定テナントの Throttle 発生をアラートで早期検知する。

詰まり: CORS Preflight で OPTIONS メソッド未定義によるブラウザ CORSエラー
REST API に GET / POST のみを定義し OPTIONS を省略したところ、SPA からのリクエストが全て CORS policy エラーでブロックされた。ブラウザは Content-Type: application/json を含む non-simple リクエストに対して事前に OPTIONS Preflight を送るが、API Gateway が 403 を返し CORS ヘッダが付かなかったためだ。

対策: REST API では各リソースに OPTIONS メソッドを定義し、統合タイプを MOCK にして Access-Control-Allow-Origin / Access-Control-Allow-Methods / Access-Control-Allow-Headers の 3 ヘッダを返す。HTTP API は cors_configuration ブロックで一括設定できるため、新規構築では HTTP API を選択することで CORS 設定ミスを防止できる。

既存 API Gateway deep-dive 記事へのクロスリンク

本節では API Gateway の認証・Throttling・CORS・Custom Domain の本番設計を解説した。Lambda Authorizer の詳細実装については専門記事で扱っている。

API Gateway 関連 deep-dive 記事


5. Step Functions 本番運用 ★山場3 — Standard vs Express × Distributed Map × Callback Pattern × Error Handling × SDK Direct

Step Functions は ASL (Amazon States Language) ベースのサーバーレスワークフローオーケストレーターです。複数の AWS サービスを宣言的に連携させ、Retry/Catch/Parallel/Map を組み合わせた本番品質のワークフローを実現します。

5-1. Standard vs Express — 選定軸

項目StandardExpress
最大実行時間1 年5 分
コスト状態遷移数課金継続時間 × リクエスト数
実行履歴Step Functions コンソールに全状態保存CloudWatch Logs のみ
一貫性Exactly-onceAt-least-once
同期実行StartSyncExecution (2分上限)StartSyncExecution (2分上限)
適用場面人手承認 / 長時間バッチ / 課金処理API Gateway バックエンド / 高頻度短時間

選定基準:
– 実行時間 5 分以内 かつ 高頻度 (1,000+ 回/秒) → Express
– 人手承認 / waitForTaskToken / 長時間実行 → Standard
– Exactly-once 保証が必要 (DB 更新 / 決済処理) → Standard
– API Gateway バックエンドで同期レスポンスが必要 → Express

5-2. Distributed Map — 大規模並列バッチ

Distributed Map は通常 Map state の拡張版で、最大 10,000 並列実行が可能です。S3 上の CSV/JSON ファイルをストリーミングで直接読み込み、数百万件規模のバッチ処理に対応します。

項目Map stateDistributed Map
最大並列数4010,000
データソースState input (メモリ)S3 / JSON 配列
Child executionStandard 履歴に含まれるStandard から分離した Child
適用スケール数百件以内数万〜数百万件
{
  "ProcessBatch": {
 "Type": "Map",
 "ItemReader": {
"Resource": "arn:aws:states:::s3:getObject",
"ReaderConfig": {
  "InputType": "CSV",
  "CSVHeaderLocation": "FIRST_ROW"
},
"Parameters": {
  "Bucket.$": "$.bucket",
  "Key.$": "$.key"
}
 },
 "MaxConcurrency": 1000,
 "ToleratedFailurePercentage": 5,
 "ItemProcessor": {
"ProcessorConfig": {
  "Mode": "DISTRIBUTED",
  "ExecutionType": "EXPRESS"
},
"StartAt": "Process",
"States": {
  "Process": {
 "Type": "Task",
 "Resource": "arn:aws:states:::lambda:invoke",
 "Parameters": {
"FunctionName": "${LambdaArn}",
"Payload.$": "$"
 },
 "End": true
  }
}
 },
 "End": true
  }
}

ExecutionType: EXPRESS により Child execution を Standard の 25K 状態履歴制限から分離します。ToleratedFailurePercentage: 5 でアイテムの 5% 失敗を許容し全体処理を継続させます。

5-3. Callback Pattern — waitForTaskToken

Callback Pattern は Step Functions が外部システムや人手処理の完了を待機するパターンです。waitForTaskToken 接尾辞リソースにより Task Token を Lambda/SQS へ渡し、処理完了後に SendTaskSuccess / SendTaskFailure を呼び出して状態機械を再開させます。

適用場面:
– 人手承認フロー (Slack 通知 → 承認ボタン → SendTaskSuccess)
– 外部 API の非同期コールバック待機
– SaaS Webhook 受信待機

sequenceDiagram
 participant SF as Step Functions
 participant Lambda as Notification Lambda
 participant Approver as Human Approver
 participant API as Callback API

 SF->>Lambda: Invoke with taskToken
 Lambda->>Approver: Slack 通知 (taskToken 埋め込み)
 Note over SF: waitForTaskToken 待機中...
 Approver->>API: 承認ボタン押下
 API->>SF: SendTaskSuccess(taskToken, output)
 SF->>SF: 次状態へ遷移

ASL 定義 (waitForTaskToken):

{
  "WaitForApproval": {
 "Type": "Task",
 "Resource": "arn:aws:states:::lambda:invoke.waitForTaskToken",
 "Parameters": {
"FunctionName": "${NotificationLambdaArn}",
"Payload": {
  "taskToken.$": "$$.Task.Token",
  "requestId.$": "$.requestId"
}
 },
 "HeartbeatSeconds": 86400,
 "Catch": [
{
  "ErrorEquals": ["States.HeartbeatTimeout"],
  "Next": "ApprovalTimeout",
  "ResultPath": "$.error"
}
 ],
 "Next": "ProcessApproval"
  }
}

HeartbeatSeconds: 86400 (24時間) を設定し、承認が来ない場合は HeartbeatTimeout として Catch で補足します。Task Token は $$.Task.Token (Context Object) から取得します。

5-4. Error Handling — Retry / Catch / 指数バックオフ

Step Functions の Error Handling は ASL レベルで宣言します。Lambda の一時的な失敗には Retry、恒久的な失敗には Catch を使います。

{
  "CallLambda": {
 "Type": "Task",
 "Resource": "arn:aws:states:::lambda:invoke",
 "Parameters": {
"FunctionName": "${LambdaArn}",
"Payload.$": "$"
 },
 "Retry": [
{
  "ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException"],
  "IntervalSeconds": 2,
  "MaxAttempts": 3,
  "BackoffRate": 2.0
}
 ],
 "Catch": [
{
  "ErrorEquals": ["States.ALL"],
  "Next": "HandleError",
  "ResultPath": "$.error"
}
 ],
 "Next": "Done"
  }
}
  • BackoffRate: 2.0: 指数バックオフ。初回 2 秒 → 4 秒 → 8 秒
  • ResultPath: "$.error": Catch 後のエラー情報を入力 JSON にマージして次状態へ渡す
  • DLQ パターン: Catch → SQS SendMessage (SDK Direct) → Lambda で非同期デッドレター処理

5-5. SDK Direct Integration — Lambda不要で AWS API を直接呼び出し

SDK Direct Integration は Lambda を介さずに 200 以上の AWS API を ASL から直接呼び出せる機能です。Lambda 実行コスト・コールドスタート・ボイラープレートを排除できます。

リソース用途
arn:aws:states:::dynamodb:putItem結果の永続化
arn:aws:states:::sqs:sendMessageキューイング / DLQ
arn:aws:states:::sns:publish通知送信
arn:aws:states:::ecs:runTask.syncコンテナバッチ実行
arn:aws:states:::bedrock:invokeModelLLM 推論
{
  "PersistResult": {
 "Type": "Task",
 "Resource": "arn:aws:states:::dynamodb:putItem",
 "Parameters": {
"TableName": "${TableName}",
"Item": {
  "pk":  {"S.$": "$.orderId"},
  "status": {"S": "COMPLETED"},
  "updatedAt": {"S.$": "$$.Execution.StartTime"}
}
 },
 "ResultPath": null,
 "Next": "Done"
  }
}

ResultPath: null は SDK 戻り値を破棄し、入力 JSON をそのまま次状態へ渡す慣用パターンです。

5-6. ASL 設計 + I/O Filter

State 種別:

State用途
TaskAWS サービス呼び出し (Lambda / SDK Direct)
Choice条件分岐
Wait固定時間 / タイムスタンプ待機
Parallel並列実行ブランチ
Map配列処理 (通常 / Distributed)
Pass入力変換・定数注入

I/O Filter パイプライン: 入力 → InputPath → Parameters → Task → ResultSelector → ResultPath → OutputPath → 次状態

State payload 上限は 256KB です。大容量データは S3 に書き出し、Key だけをポインタとして渡す External Payload Pattern を採用してください。

5-7. deep-dive 記事クロスリンク

Step Functions の各機能はそれぞれ独立した deep-dive シリーズで詳細解説しています。

  • Standard vs Express 選定: Step Functions Express vs Standard Production — 詳細比較・移行ガイド
  • 大規模並列: Step Functions Distributed Map Production — S3 ソース設計・Concurrency 制御
  • 人手承認: Step Functions Callback waitForTaskToken — Slack 連携・Webhook 実装詳細
  • 障害対応: Step Functions Error Handling — Retry 設計・DLQ 連携・部分失敗ハンドリング
  • コスト削減: Step Functions SDK Direct Integration Production — 200+ API 活用レシピ

5-8. Terraform 実装例

fig04: Step Functions Standard vs Express + Distributed Map アーキテクチャ

# Standard ステートマシン (人手承認 + Callback + Error Handling)
resource "aws_sfn_state_machine" "approval" {
  name  = "${var.project}-approval"
  role_arn = aws_iam_role.sfn.arn
  type  = "STANDARD"

  definition = jsonencode({
 Comment = "Standard: waitForTaskToken Callback + Error Handling"
 StartAt = "WaitForApproval"
 States = {
WaitForApproval = {
  Type  = "Task"
  Resource = "arn:aws:states:::lambda:invoke.waitForTaskToken"
  Parameters = {
 FunctionName = aws_lambda_function.notifier.arn
 Payload = {
"taskToken.$" = "$$.Task.Token"
"requestId.$" = "$.requestId"
 }
  }
  HeartbeatSeconds = 86400
  Retry = [{
 ErrorEquals  = ["Lambda.ServiceException"]
 IntervalSeconds = 2
 MaxAttempts  = 3
 BackoffRate  = 2.0
  }]
  Catch = [{
 ErrorEquals = ["States.ALL"]
 Next  = "HandleError"
 ResultPath  = "$.error"
  }]
  Next = "Done"
}
Done  = { Type = "Succeed" }
HandleError = { Type = "Fail", Error = "WorkflowFailed" }
 }
  })

  logging_configuration {
 log_destination  = "${aws_cloudwatch_log_group.sfn.arn}:*"
 include_execution_data = true
 level= "ERROR"
  }

  tags = var.common_tags
}

# Distributed Map ステートマシン (S3 CSV 大規模並列バッチ)
resource "aws_sfn_state_machine" "batch" {
  name  = "${var.project}-batch"
  role_arn = aws_iam_role.sfn.arn
  type  = "STANDARD"

  definition = jsonencode({
 Comment = "Distributed Map: S3 CSV parallel batch"
 StartAt = "ProcessBatch"
 States = {
ProcessBatch = {
  Type = "Map"
  ItemReader = {
 Resource = "arn:aws:states:::s3:getObject"
 ReaderConfig = {
InputType= "CSV"
CSVHeaderLocation = "FIRST_ROW"
 }
 Parameters = {
"Bucket.$" = "$.bucket"
"Key.$" = "$.key"
 }
  }
  MaxConcurrency = 1000
  ToleratedFailurePercentage = 5
  ItemProcessor = {
 ProcessorConfig = {
Mode = "DISTRIBUTED"
ExecutionType = "EXPRESS"
 }
 StartAt = "Process"
 States = {
Process = {
  Type  = "Task"
  Resource = "arn:aws:states:::lambda:invoke"
  Parameters = {
 FunctionName = aws_lambda_function.processor.arn
 "Payload.$"  = "$"
  }
  End = true
}
 }
  }
  End = true
}
 }
  })

  tags = var.common_tags
}
事故事例: Map state で 25K 状態履歴制限に抵触して実行が強制終了
あるバッチ処理で通常 Map state を使用して 50,000 件を並列処理した結果、Standard ステートマシンの 1 Execution あたり 25,000 状態遷移上限を超過し、実行が強制終了されました。再試行してもすべて同じ上限で失敗するため、バッチ処理が完全停止しました。Distributed Map + Express Child execution への書き直しで根本解決しました。

対処パターン:
1. 数百件を超えるアイテムを並列処理する設計は最初から Distributed Map を採用する
2. ExecutionType: EXPRESS で Child execution を Standard 履歴から分離し、25K 制限を回避する
3. ToleratedFailurePercentage を設定し、一部アイテム失敗時も全体処理が継続されるよう設計する

設計ミス: Express 最大実行時間 5 分超過で Standard への作り直しが発生
Express ステートマシンで実装した推論パイプラインが、本番データ量の増加に伴い実行時間が 5 分を超過し始め、実行が自動終了されるようになりました。Express は 5 分が絶対上限のため設定変更での対処は不可能で、ステートマシンを Standard に作り直す対応が必要になりました。

対処パターン:
1. 実行時間が 5 分を超える可能性があるワークフローは設計時点で Standard を選択する
2. Express を使用する場合は Lambda Timeout の合計 + Step Functions オーバーヘッドが 4 分以内に収まることを試算する
3. CloudWatch Logs Insights で Express 実行時間を定期監視し、4 分超でアラートを設定して移行判断の余地を持つ


6. 詰まりポイント7選 — Cold Start遅延 / VPC ENI / Lambda timeout / APIGW throttle / SF状態爆発 / IAM hell / Cost runaway

詰まり1: Cold Start p99 遅延 — VPC ENI 初期化 + 大型 Container Image が重なると 8 秒超

発生パターン: Lambda 関数が VPC 接続かつ Container Image デプロイ (1 GB 超) かつ Java ランタイムという三重苦の場合、コールドスタート時に VPC ENI 割り当て + Container Image pull + JVM 起動 が直列で発生し、p99 が 8〜12 秒に達することがある。API Gateway のタイムアウトは最大 29 秒であるため、バースト時に Throttle や 504 エラーが多発する。

対処パターン:
1. Provisioned Concurrency: ウォームアップ済みインスタンスを常時確保し、コールドスタートを排除する。Auto Scaling Schedule と組み合わせてコストを抑制する
2. SnapStart (Java/Python/.NET): 初期化フェーズのスナップショットを取得し、再利用することで JVM 起動コストを大幅削減
3. Container Image を最小化 (multi-stage build / Lambda-specific base image 使用)
4. VPC 不要な処理は VPC 外 Lambda に分離する

# Provisioned Concurrency + Auto Scaling スケジュール
resource "aws_lambda_provisioned_concurrency_config" "api" {
  function_name= aws_lambda_function.api.function_name
  qualifier = aws_lambda_alias.live.name
  provisioned_concurrent_executions = 10
}

resource "aws_appautoscaling_target" "lambda_pc" {
  max_capacity = 50
  min_capacity = 5
  resource_id  = "function:${aws_lambda_function.api.function_name}:${aws_lambda_alias.live.name}"
  scalable_dimension = "lambda:function:ProvisionedConcurrency"
  service_namespace  = "lambda"
}

resource "aws_appautoscaling_scheduled_action" "scale_up" {
  name= "scale-up-business-hours"
  service_namespace  = "lambda"
  resource_id  = aws_appautoscaling_target.lambda_pc.resource_id
  scalable_dimension = aws_appautoscaling_target.lambda_pc.scalable_dimension
  schedule  = "cron(0 8 * * ? *)"

  scalable_target_action {
 min_capacity = 20
 max_capacity = 50
  }
}

詰まり2: VPC ENI 枯渇 — 旧設計で同時実行ごとに ENI 1個消費

発生パターン: 2019年以前の古い Lambda VPC 設計では、同時実行数 1 件につき 1 ENI を消費していた。Hyperplane ENI 共有 (2019年以降のデフォルト) が適用されていない古い関数や、Subnet の利用可能 IP が枯渇した場合、新規 Lambda 実行が「ENI 取得待ち」でタイムアウトする。

対処パターン:
1. Subnet の利用可能 IP 数を確認する (/24 以上が推奨。Lambda は Hyperplane 共有でも Subnet IP を消費する)
2. 複数 AZ の Subnet を指定して VPC Config を設定することで、ENI リソースを分散する
3. Lambda 関数の VPC Config を更新すると Hyperplane ENI 共有が自動適用される
4. CloudWatch Metrics の ENILimit / VPCResourceCheckFailure を監視してアラームを設定する

resource "aws_lambda_function" "api" {
  function_name = "my-api-handler"
  runtime = "python3.12"
  handler = "app.handler"
  filename= "lambda.zip"
  role = aws_iam_role.lambda_exec.arn

  # ✅ 複数AZ の Subnet を指定 (Hyperplane ENI 共有 + IP 分散)
  vpc_config {
 subnet_ids= [
aws_subnet.private_a.id,
aws_subnet.private_b.id,
aws_subnet.private_c.id,
 ]
 security_group_ids = [aws_security_group.lambda.id]
  }

  memory_size = 512
  timeout  = 30
}

詰まり3: Lambda Timeout vs API Gateway 29秒制限の衝突

発生パターン: API Gateway (REST API) の統合タイムアウトは最大 29 秒 (HTTP API は最大 30 秒) に固定されている。Lambda 側のタイムアウトを 60 秒に設定しても、API Gateway 側が 29 秒で接続を切断するため、処理中の Lambda が 504 Error を返す。バッチ処理や外部 API 呼び出しを含む処理で頻発する。

対処パターン:
1. 非同期パターン: API Gateway → Lambda (SQS/EventBridge キューへエンキュー) → 202 Accepted を即返却。処理は別 Lambda が非同期で実行
2. Step Functions オフロード: 長時間処理を Step Functions State Machine に委譲し、実行 ARN を返却。クライアントはポーリングまたは Callback で結果を受け取る
3. WebSocket API を使用してリアルタイム結果通知を実現する

# SQS 非同期処理パターン: API Lambda は即エンキューして 202 返却
resource "aws_sqs_queue" "job_queue" {
  name = "job-queue"
  visibility_timeout_seconds = 300
  message_retention_seconds  = 86400
}

resource "aws_lambda_event_source_mapping" "worker" {
  event_source_arn = aws_sqs_queue.job_queue.arn
  function_name = aws_lambda_function.worker.arn
  batch_size = 1

  function_response_types = ["ReportBatchItemFailures"]
}

詰まり4: API Gateway Throttling — Account-level 制限で全テナントが被害を受ける

発生パターン: API Gateway の Account-level デフォルト Throttle は 10,000 rps (バースト 5,000) であり、Usage Plan を設定しないと全ての Stage・Method がこの共通上限を使い合う。1 テナントが大量リクエストを送信すると Account-level 上限に達し、他の全テナントへのレスポンスも 429 Too Many Requests になる。

対処パターン:
1. Stage-level Throttle で API 全体の上限を設定する
2. Method-level Throttle で重要エンドポイントに細かい制限を設ける
3. Usage Plan + API Key でテナント別に Throttle 枠を分離し、1 テナントの暴走が他テナントに波及しないようにする

# API Gateway Usage Plan でテナント別スロットリング
resource "aws_api_gateway_usage_plan" "standard" {
  name  = "standard-plan"
  description = "Standard tier: 100 rps / 10000 daily"

  api_stages {
 api_id = aws_api_gateway_rest_api.app.id
 stage  = aws_api_gateway_stage.prod.stage_name
  }

  throttle_settings {
 rate_limit  = 100# rps per API Key
 burst_limit = 200
  }

  quota_settings {
 limit  = 10000
 period = "DAY"
  }
}

resource "aws_api_gateway_api_key" "tenant_a" {
  name = "tenant-a-key"
}

resource "aws_api_gateway_usage_plan_key" "tenant_a" {
  key_id  = aws_api_gateway_api_key.tenant_a.id
  key_type= "API_KEY"
  usage_plan_id = aws_api_gateway_usage_plan.standard.id
}

詰まり5: Step Functions 状態爆発 — Map state で履歴 25K 制限に抵触

発生パターン: Step Functions Standard Workflow の実行履歴は 25,000 イベント上限がある。Map state で 1,000 件の子 Iteration を実行すると、各 Iteration の START/END イベントだけで 2,000 イベントを消費する。結果として数万件の処理で履歴上限を超え、実行が強制終了する。

対処パターン:
1. Distributed Map に移行する — 子 Workflow を別の State Machine Execution として起動するため、親の履歴にカウントされない。10,000 並列まで対応し、S3 オブジェクト/JSON 配列を直接ソースとして読み込める
2. バッチサイズを分割して直接 Map state の Iteration 数を 25K 以下に抑える (小規模の場合)
3. Express Workflow を子 State Machine として組み合わせることで、履歴を親から分離できる

{
  "Type": "Map",
  "ItemProcessor": {
 "ProcessorConfig": {
"Mode": "DISTRIBUTED",
"ExecutionType": "EXPRESS"
 },
 "StartAt": "ProcessItem",
 "States": {
"ProcessItem": {
  "Type": "Task",
  "Resource": "arn:aws:states:::lambda:invoke",
  "Parameters": {
 "FunctionName": "process-item",
 "Payload.$": "$"
  },
  "End": true
}
 }
  },
  "ItemsPath": "$.items",
  "MaxConcurrency": 100,
  "ToleratedFailurePercentage": 5
}

詰まり6: IAM Role 設計の複雑化 — Serverless 4 Role を整理する

発生パターン: Serverless アーキテクチャでは Lambda Function Role / Step Functions Role / API Gateway Logging Role / EventBridge Scheduler Role の4種類の IAM Role が必要になる。各 Role の Trust Policy と Permission Policy を把握せずに設計すると、「なぜかこの Role では DynamoDB にアクセスできない」「Step Functions が Lambda を呼べない」等の権限エラーが多発する。

責務分離設計:

| Role | Trust Principal | 最小権限 |
|——|—————-|———|
| Lambda Function Role | lambda.amazonaws.com | 対象 DynamoDB/S3/SQS への個別 Action |
| Step Functions Role | states.amazonaws.com | Lambda Invoke / SQS Send / SNS Publish 等 |
| API Gateway Role | apigateway.amazonaws.com | CloudWatch Logs への書き込みのみ |
| EventBridge Scheduler Role | scheduler.amazonaws.com | Step Functions StartExecution / Lambda Invoke |

# Step Functions に Lambda 起動権限を付与
resource "aws_iam_role" "sfn_exec" {
  name = "sfn-execution-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "states.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })
}

resource "aws_iam_role_policy" "sfn_lambda" {
  name = "sfn-invoke-lambda"
  role = aws_iam_role.sfn_exec.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect= "Allow"
  Action= ["lambda:InvokeFunction"]
  Resource = [aws_lambda_function.processor.arn]
},
{
  Effect= "Allow"
  Action= ["logs:CreateLogGroup", "logs:CreateLogDelivery", "logs:PutLogEvents"]
  Resource = "arn:aws:logs:*:*:*"
}
 ]
  })
}

詰まり7: Cost Runaway — Provisioned Concurrency 過剰確保と Standard Workflow 過剰実行

発生パターン: Provisioned Concurrency は確保した数 × 時間でコストが発生する ($0.0000646 / 関数秒)。業務時間外も 50 並列を確保し続けると、月額で数万円の不要なコストが発生する。また Step Functions Standard Workflow は 1 状態遷移 $0.000025 であり、高頻度 Workflow (秒単位ポーリング等) を Standard で実装すると月額で数百ドルになる。

対処パターン:
1. Provisioned Concurrency の Auto Scaling Schedule を設定し、業務時間外は最小値 (2〜5 など) に削減する
2. 高頻度 Workflow (実行時間 5 分以内) は Express Workflow ($1.00 / 100 万実行 + GB 秒) に切り替える
3. CloudWatch Metrics の ProvisionedConcurrencyInvocations / ProvisionedConcurrencySpilloverInvocations を監視して適切な PC 数を調整する
4. Cost Explorer で Lambda / Step Functions のコストを分離タグでトラッキングする

# Provisioned Concurrency: 夜間スケールダウンスケジュール
resource "aws_appautoscaling_scheduled_action" "scale_down" {
  name= "scale-down-night"
  service_namespace  = "lambda"
  resource_id  = aws_appautoscaling_target.lambda_pc.resource_id
  scalable_dimension = aws_appautoscaling_target.lambda_pc.scalable_dimension
  schedule  = "cron(0 20 * * ? *)"

  scalable_target_action {
 min_capacity = 2
 max_capacity = 5
  }
}

# Step Functions Express Workflow: 高頻度処理向け
resource "aws_sfn_state_machine" "express_processor" {
  name  = "high-frequency-processor"
  type  = "EXPRESS"  # ✅ 高頻度 → Express
  role_arn = aws_iam_role.sfn_exec.arn

  definition = jsonencode({
 Comment = "High-frequency processor (Express)"
 StartAt = "Process"
 States = {
Process = {
  Type  = "Task"
  Resource = aws_lambda_function.processor.arn
  End= true
}
 }
  })

  logging_configuration {
 level= "ERROR"
 include_execution_data = false
 log_destination  = "${aws_cloudwatch_log_group.sfn_express.arn}:*"
  }
}

7. アンチパターン→正解パターン変換演習 (5件)

▶ 演習5問の解答を確認する


演習1: 壊れた Lambda + VPC — Subnet 1個 で ENI 枯渇

Before (アンチパターン):

resource "aws_lambda_function" "api" {
  function_name = "my-api"
  runtime = "python3.12"
  handler = "app.handler"
  filename= "lambda.zip"
  role = aws_iam_role.lambda_exec.arn

  # ❌ Subnet 1個のみ → 1 AZ に ENI が集中 / IP が枯渇すると起動不可
  vpc_config {
 subnet_ids= [aws_subnet.private_a.id]
 security_group_ids = [aws_security_group.lambda.id]
  }
}

After (正解パターン):

resource "aws_lambda_function" "api" {
  function_name = "my-api"
  runtime = "python3.12"
  handler = "app.handler"
  filename= "lambda.zip"
  role = aws_iam_role.lambda_exec.arn

  # ✅ 3 AZ の Subnet を指定 — ENI 分散 + AZ 障害に対する耐障害性
  vpc_config {
 subnet_ids = [
aws_subnet.private_a.id,
aws_subnet.private_b.id,
aws_subnet.private_c.id,
 ]
 security_group_ids = [aws_security_group.lambda.id]
  }

  memory_size = 512
  timeout  = 30

  # Provisioned Concurrency でコールドスタート排除
  publish = true
}

resource "aws_lambda_alias" "live" {
  name = "live"
  function_name = aws_lambda_function.api.function_name
  function_version = aws_lambda_function.api.version
}

resource "aws_lambda_provisioned_concurrency_config" "api" {
  function_name = aws_lambda_function.api.function_name
  qualifier  = aws_lambda_alias.live.name
  provisioned_concurrent_executions  = 5
}

解説: Lambda VPC 接続では Hyperplane ENI 共有が自動適用されるが、Subnet の利用可能 IP が枯渇するとENI 割り当てに失敗して起動できなくなる。3 AZ の Subnet を指定することで IP アドレス空間を 3 倍に広げ、AZ 障害時の自動切替も確保する。Subnet は /24 以上 (254 IP) を推奨し、他のリソースと IP 空間を共有しないよう Lambda 専用 Subnet を設けるとより安全。


演習2: 壊れた API Gateway — Usage Plan 未設定で Account-level Throttle に抵触

Before (アンチパターン):

resource "aws_api_gateway_rest_api" "app" {
  name = "my-app-api"
}

resource "aws_api_gateway_stage" "prod" {
  rest_api_id= aws_api_gateway_rest_api.app.id
  stage_name = "prod"
  deployment_id = aws_api_gateway_deployment.app.id
  # ❌ Usage Plan なし → Account-level 10,000 rps を全 API で共有
  # ❌ Stage-level Throttle なし → 無制限アクセス可
}

After (正解パターン):

resource "aws_api_gateway_rest_api" "app" {
  name = "my-app-api"
}

resource "aws_api_gateway_stage" "prod" {
  rest_api_id= aws_api_gateway_rest_api.app.id
  stage_name = "prod"
  deployment_id = aws_api_gateway_deployment.app.id

  # ✅ Stage-level Throttle (全 Method のデフォルト上限)
  default_route_settings {
 throttling_rate_limit  = 500
 throttling_burst_limit = 1000
  }
}

# ✅ Usage Plan でテナント別 Throttle 管理
resource "aws_api_gateway_usage_plan" "standard" {
  name = "standard-plan"

  api_stages {
 api_id = aws_api_gateway_rest_api.app.id
 stage  = aws_api_gateway_stage.prod.stage_name
  }

  throttle_settings {
 rate_limit  = 100
 burst_limit = 200
  }

  quota_settings {
 limit  = 50000
 period = "DAY"
  }
}

resource "aws_api_gateway_api_key" "tenant_a" {
  name = "tenant-a"
}

resource "aws_api_gateway_usage_plan_key" "tenant_a" {
  key_id  = aws_api_gateway_api_key.tenant_a.id
  key_type= "API_KEY"
  usage_plan_id = aws_api_gateway_usage_plan.standard.id
}

解説: Usage Plan なしで運用すると、悪意ある/バグのある 1 クライアントがリクエストを大量送信してAccount-level Throttle (10,000 rps) を使い切り、同アカウントの全 API が影響を受ける。Usage Plan + API Key でテナントごとにレート制限を設けることで影響範囲を 1 テナントに限定できる。


演習3: 壊れた Step Functions Map state — 25K 履歴制限に抵触

Before (アンチパターン):

{
  "Comment": "Process 100k items — WRONG: Standard Map state hits 25K event limit",
  "StartAt": "ProcessAll",
  "States": {
 "ProcessAll": {
"Type": "Map",
"ItemsPath": "$.items",
"MaxConcurrency": 100,
"Iterator": {
  "StartAt": "ProcessOne",
  "States": {
 "ProcessOne": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
  "FunctionName": "process-item",
  "Payload.$": "$"
},
"End": true
 }
  }
},
"End": true
 }
  }
}

After (正解パターン — Distributed Map):

{
  "Comment": "Process 100k items — Distributed Map: child executions are separate",
  "StartAt": "ProcessAll",
  "States": {
 "ProcessAll": {
"Type": "Map",
"ItemProcessor": {
  "ProcessorConfig": {
 "Mode": "DISTRIBUTED",
 "ExecutionType": "EXPRESS"
  },
  "StartAt": "ProcessOne",
  "States": {
 "ProcessOne": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
  "FunctionName": "process-item",
  "Payload.$": "$"
},
"End": true
 }
  }
},
"ItemsPath": "$.items",
"MaxConcurrency": 1000,
"ToleratedFailurePercentage": 5,
"ResultWriter": {
  "Resource": "arn:aws:states:::s3:putObject",
  "Parameters": {
 "Bucket": "results-bucket",
 "Prefix": "results/"
  }
},
"End": true
 }
  }
}

解説: Standard Workflow の inline Map state は各 Iteration のイベント (Start/End 等) が親 Execution の履歴にカウントされる。10 万件では 20 万+ イベントとなり 25K 制限を大幅に超える。Distributed Map は子 Iteration を独立した Express Execution として起動するため、親の履歴消費を最小化しつつ最大 10,000 並列まで処理できる。


演習4: 壊れた Step Functions Callback — waitForTaskToken 未送信で永久待ち

Before (アンチパターン):

{
  "Comment": "WRONG: Task Token not sent to external system",
  "StartAt": "RequestApproval",
  "States": {
 "RequestApproval": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
  "FunctionName": "send-approval-request",
  "Payload": {
 "action": "approve",
 "data.$": "$.requestData"
  }
},
"HeartbeatSeconds": 3600,
"Next": "ApprovalResult"
 },
 "ApprovalResult": {
"Type": "Pass",
"End": true
 }
  }
}

After (正解パターン):

{
  "Comment": "CORRECT: waitForTaskToken — Lambda receives token and sends it back",
  "StartAt": "RequestApproval",
  "States": {
 "RequestApproval": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke.waitForTaskToken",
"Parameters": {
  "FunctionName": "send-approval-request",
  "Payload": {
 "taskToken.$": "$$.Task.Token",
 "action": "approve",
 "data.$": "$.requestData"
  }
},
"HeartbeatSeconds": 86400,
"Catch": [{
  "ErrorEquals": ["States.HeartbeatTimeout"],
  "Next": "ApprovalTimeout"
}],
"Next": "ApprovalResult"
 },
 "ApprovalResult": {
"Type": "Pass",
"End": true
 },
 "ApprovalTimeout": {
"Type": "Fail",
"Error": "ApprovalTimedOut",
"Cause": "No response within 24 hours"
 }
  }
}
import boto3
import json

sfn = boto3.client('stepfunctions')

def handler(event, context):
 task_token = event['taskToken']
 action = event['action']
 request_data = event['data']

 # 承認リクエストをメール/Slack等で送信
 send_approval_request(
  approval_url=f"https://approval.example.com/approve?token={task_token}",
  data=request_data
 )
 # Lambda はここで return — Step Functions は Token の返却を待機
 return {"status": "approval_requested"}

def send_approval_request(approval_url, data):
 print(f"Approval URL: {approval_url}")

# 承認完了時に呼ばれる別エンドポイント (API Gateway 経由等)
def approve_handler(event, context):
 body = json.loads(event.get('body', '{}'))
 task_token = body['taskToken']

 sfn.send_task_success(
  taskToken=task_token,
  output=json.dumps({"approved": True, "approver": body.get("approver")})
 )
 return {"statusCode": 200, "body": "Approved"}

解説: waitForTaskToken リソースを使わずに通常の lambda:invoke を指定すると、Step Functions は Lambda の実行完了をもって次状態に遷移する。外部承認の「結果を待つ」意図が実現されない。$.$.Task.Token で Task Token を Lambda に渡し、Lambda は外部システムへトークン付きの承認 URL を送信。承認後に send_task_success でトークンを返却することで Workflow が再開する。


演習5: 壊れた Lambda IAM Role — AdministratorAccess で最小特権違反

Before (アンチパターン):

# ❌ AdministratorAccess 付与 — 全 AWS リソースを操作可能
resource "aws_iam_role_policy_attachment" "lambda_admin" {
  role = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

After (正解パターン):

# ✅ 最小特権: DynamoDB + SQS への特定操作のみ許可
resource "aws_iam_role" "lambda_exec" {
  name = "lambda-api-exec-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_basic" {
  role = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}

resource "aws_iam_role_policy" "lambda_app" {
  name = "lambda-app-permissions"
  role = aws_iam_role.lambda_exec.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect = "Allow"
  Action = [
 "dynamodb:GetItem",
 "dynamodb:PutItem",
 "dynamodb:UpdateItem",
 "dynamodb:Query",
  ]
  Resource = [
 aws_dynamodb_table.orders.arn,
 "${aws_dynamodb_table.orders.arn}/index/*",
  ]
},
{
  Effect= "Allow"
  Action= ["sqs:SendMessage", "sqs:GetQueueAttributes"]
  Resource = [aws_sqs_queue.job_queue.arn]
}
 ]
  })
}

解説: Lambda Function Role に AdministratorAccess を付与すると、コードのバグや脆弱性を突かれた際にアカウント全体のリソースが侵害される。DynamoDB は対象テーブルの特定 Action のみ、SQS は対象キューのみに絞った最小特権ポリシーを作成する。AWSLambdaVPCAccessExecutionRole (VPC ENI 管理 + CloudWatch Logs 書き込み) は VPC 接続 Lambda では必須のマネージドポリシーとして別途アタッチする。


8. まとめ + Vol2予告 + 落とし穴10選 + 全11軸クロスリンク + 第12軸完結宣言

Vol1 振り返り — 3本柱 × Workload 別選定マトリクス

本記事で習得した Serverless 本番運用 3 本柱の全体像を整理する。

3本柱代表サービス得意 Workload本番必須設定
ComputeLambdaイベント駆動・短時間処理・API バックエンドProvisioned Concurrency + Multi-AZ Subnet
APIAPI GatewayHTTP/WebSocket API 公開・認証・ThrottleUsage Plan + Stage Throttle + Custom Domain
WorkflowStep Functions長時間処理・承認フロー・バッチ並列Distributed Map + Callback Pattern + Express選定

全11軸との統合視点:
IAM × Serverless: Lambda 最小特権 / Step Functions Role 責務分離 / API Gateway Logging Role
EKS × Serverless: EKS ワークロードから SQS 経由で Lambda を非同期トリガー
復旧 × Serverless: Dead Letter Queue + Step Functions 再実行 + Lambda 関数バージョン管理
コスト × Serverless: Provisioned Concurrency Schedule / Express vs Standard 選定 / Memory 最適化
マルチアカウント × Serverless: Cross-Account Lambda Invoke / Step Functions cross-account
Observability × Serverless: Lambda Insights + X-Ray / Step Functions Execution 可視化
Network × Serverless: Lambda VPC Endpoint / API Gateway Private API / PrivateLink
DevOps × Serverless: SAM Pipeline / CDK Deploy / Lambda Layer バージョン管理
Database × Serverless: RDS Proxy 経由で Lambda から RDS 接続 / DynamoDB Streams → Lambda


落とし穴10選

  1. Lambda Cold Start で VPC ENI 8秒遅延 — VPC + Container Image + Java の三重苦。Provisioned Concurrency で排除する
  2. Lambda メモリ 128MB で CPU bottleneck — Lambda のCPU はメモリに比例。低メモリでは計算処理が遅く逆にコスト高になることも
  3. Lambda Container Image が 10 GB 上限に触れる — デプロイパッケージ制限。multi-stage build で不要な依存を削除する
  4. API Gateway Throttle 設定漏れ — Usage Plan なしで Account-level 10,000 rps を全テナントで共有
  5. API Gateway CORS Preflight OPTIONS 未定義 — ブラウザからの Cross-Origin リクエストが OPTIONS で失敗する
  6. Step Functions Express 5分上限超過 — Express は最長 5 分。長時間処理は Standard に切替が必要
  7. Distributed Map 未使用で 25K 状態制限に抵触 — 大量 Iteration は Standard Map state では履歴超過する
  8. Step Functions Callback Token 未送信lambda:invoke のまま実装すると Token を渡せず外部承認が永久待ちになる
  9. Lambda Function Role に AdministratorAccess 付与 — 最小特権に絞らないとコード脆弱性がアカウント全体の侵害につながる
  10. Provisioned Concurrency 過剰確保で Cost runaway — 業務時間外スケールダウンと Auto Scaling Schedule を忘れずに設定する

本番 Go-Live チェックリスト

  • [ ] Lambda は 3 AZ の Subnet を指定し、Provisioned Concurrency を設定している
  • [ ] Lambda Function Role は最小特権 (対象リソースへの特定 Action のみ) になっている
  • [ ] API Gateway Stage に Throttle (Rate/Burst) が設定されている
  • [ ] 複数テナントを扱う場合は Usage Plan + API Key でテナント分離している
  • [ ] 10 万件超のバッチ処理は Distributed Map を使用している
  • [ ] Callback Pattern では waitForTaskToken リソースを指定し Token を外部に送付している
  • [ ] 高頻度 Workflow (5 分以内) は Express Workflow を選択している
  • [ ] Provisioned Concurrency の業務時間外スケールダウンスケジュールが設定されている
  • [ ] Lambda から RDS に接続する場合は RDS Proxy を経由している
  • [ ] Step Functions の実行ログが CloudWatch Logs に出力されている (Level: ERROR 以上)
  • [ ] API Gateway のアクセスログが有効化されており、Custom Log Format で必要なフィールドを記録している

Vol2 公開中 — EventBridge × SQS × SNS × Kinesis 本番運用

Vol2 では Event-Driven Architecture の4本柱 (EventBridge × SQS × SNS × Kinesis) を本番運用視点で解説する。非同期処理・イベントルーティング・メッセージキュー・ストリーム処理の本番品質パターンを確立する。

Vol2 で扱う技術主なユースケース
EventBridgeイベントルーティング / スケジュール / クロスアカウント連携
SQS非同期キュー / DLQ / FIFO / Lambda トリガー
SNSFan-out / モバイルプッシュ / Lambda 連携
Kinesis Data Streamsリアルタイムストリーム処理 / シャード設計

全11軸 (23記事) + Serverless Vol1 — 全24記事クロスリンク


第12軸 Serverless本番運用 シリーズ起点 完結宣言

本記事により、AWS本番運用 第12軸 = Serverless本番運用 シリーズが起点 Vol1 から始動しました。

全11軸 (IAM/EKS/復旧/AI/セキュリティ/コスト/マルチアカウント/Observability/Network/DevOps/Database) の 23 記事で構築した本番運用基盤の上に、Lambda × API Gateway × Step Functions の Serverless 実行層 を加えることで、AWS 本番システムのサーバーレスワークロードが完全統合されます。

Vol2 では Event-Driven Architecture (EventBridge × SQS × SNS × Kinesis) の4本柱を本番運用視点で解説します。