مرکزی مواد پر جائیں
友田 陽大
AWS Lambda in production
AWS
Lambda
サーバーレス
アーキテクチャ設計
冪等性

AWS Lambda 本番運用ガイド:実行モデル・冪等性・可観測性・セキュリティ・コストを公式仕様で固める

AWS Lambdaを本番品質で設計・運用するための実装ガイド。3フェーズの実行環境ライフサイクル、ハンドラ外での接続再利用、ZIP/コンテナ/レイヤーのパッケージング、同期/非同期/イベントソースの失敗設計、Powertoolsによる冪等化、構造化ログ/X-Ray、最小権限とSecrets、Arm64とメモリ調整のコスト最適化までを、AWS公式仕様に忠実な実コードで解説します。

Published
Reading time
23 min read
Author
友田 陽大
شیئر کریں

「サーバー管理から解放されて、イベントに反応するコードだけ書きたい」——AWS Lambda を選ぶ動機は一行で言えます。けれど本番に載せた瞬間、問いが一気に増えます。同じイベントが2回来たら? 起動が遅い(コールドスタート)のはなぜ? DBコネクションは毎回張り直すのか? 失敗したイベントはどこへ消えるのか? 秘密情報はどこに置くのか? そして請求書はなぜこの金額なのか?

この記事は、AWS Lambda を本番品質で設計・運用するための実装ガイドです。題材として、私が中核開発者(主要開発者3名)として構築した、環境・カーボンクレジット/地域通貨のマルチテナント決済プラットフォーム(サーバーレス決済プラットフォームの信頼性設計)での設計判断も交えます。本番稼働中の二重課金・残高不整合 0件を、冪等性・失敗設計・可観測性で支えた実例です。

この記事のルール:Lambda の仕様・パラメータ名・既定値・クォータは AWS 公式ドキュメント(2026年6月時点) に基づきます。クォータや料金は改定され、リージョンや新規アカウントで初期値が異なります。本番投入前に必ず公式の各ページ(末尾「参考」)で最新値を確認してください。最重要の前提:Lambda は「少なくとも1回(at-least-once)」起動されうる。リトライは異常ではなく仕様です。だから関数を冪等に作るのが、信頼性設計の出発点になります。


0. メンタルモデル:Lambda=「イベント → 使い捨ての実行環境 → 使った分だけ課金」

最初に、この記事を貫く5つのメンタルモデルを固定します。ここを腹落ちさせれば、あとの実装はすべてこの帰結です。

  • 関数=イベントハンドラ。Lambda は「リクエストを受けたら実行環境を1つ用意し、コードを走らせ、終わったら凍結(または破棄)する」サービス。サーバーは見えない。
  • 実行環境=使い捨て、でも一定時間は再利用される。同時リクエストごとに別々の実行環境が割り当てられる(=同時実行数)。1つの環境は終わると凍結され、しばらく次の呼び出しで再利用(ウォームスタート)される。
  • ハンドラ外=1度だけ、ハンドラ内=毎回。コールドスタート時にハンドラ外のコード(INIT)が1度走り、以降のウォーム呼び出しではハンドラ内だけが走る。だから接続やSDKクライアントはハンドラ外で張る(第2章)。
  • 再試行は前提。非同期呼び出しもイベントソースも at-least-once。「2回来ても結果が同じ」になるよう冪等に作る(第7章)。
  • 課金は『割当メモリ × 実行時間(1ms単位)+ リクエスト数』。速くする=安くする、が基本的に一致する(第10章)。

適材適所:Lambda は「イベント駆動・スパイク追従・スケールトゥゼロ」に強く、標準関数の最大実行時間は900秒(15分)・同期ペイロードは6MBという制約があります。長時間処理・常駐サーバー・任意TCP/UDP が要るなら Fargate が本命です。どの計算基盤を選ぶかは姉妹記事 AWS Fargate vs Lambda vs App Runner 技術選定ガイド に委ね、本稿は**「Lambda を選んだ後、どう本番で作るか」**に集中します。


1. 実行環境のライフサイクル:3フェーズと「ハンドラ外」の意味

Lambda の挙動を支配するのは、実行環境(execution environment)のライフサイクルです。公式は3フェーズで説明します。

フェーズ何が起きるかいつ
Init① Extension init(拡張の起動)② Runtime init(ランタイム起動)③ Function init(ハンドラの静的コード実行)コールドスタート時に1度
Invokeハンドラ関数の実行。関数のタイムアウトはこのフェーズ全体に効くリクエストごと
Shutdown一定時間呼び出しが無いと環境を破棄。拡張に猶予を与えるアイドル後

ここで本番運用に効く事実を3つ押さえます(すべて公式に基づく)。

  • Init には10秒の制限がある(標準のオンデマンド関数)。ハンドラ外の初期化が10秒を超えると、最初の呼び出しでタイムアウト扱いになりリトライされる。重い初期化は要注意。
  • コールドスタートは全呼び出しの1%未満に収まるのが典型で、所要は「100ms未満〜1秒超」と幅がある。頻度より**裾の重さ(P99)**が問題になる。詳しくは姉妹記事 Lambda コールドスタート最適化ガイド で深掘りします。
  • 2025年8月1日から、INIT 時間も課金対象に統一された。以前は「マネージドランタイム+ZIP のオンデマンド関数」だけ INIT が無課金だったが、現在は全構成で INIT が Billed Duration に含まれる(カスタムランタイム・プロビジョンド同時実行・コンテナイメージは従来から課金)。コールドスタートの初期化はもうタダではない——これは第10章のコスト設計に直結します。

1.1 「ハンドラ外で接続を張る」が最重要パターン

凍結された実行環境はメモリ状態ごと再利用されます。公式も明言する通り、ハンドラ外で宣言したオブジェクトはウォーム呼び出し間で生き続ける。だから DB 接続・SDK クライアントはハンドラで1度だけ初期化し、再利用します。これを怠ると毎回接続を張り直し、レイテンシとコストとコネクション枯渇を招きます。

// handler.ts — 「薄いアダプタ」。重い初期化はハンドラ外(INIT)で1度だけ。
import { Logger } from "@aws-lambda-powertools/logger";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
import type { SQSEvent, SQSBatchResponse, Context } from "aws-lambda";

// ── INIT フェーズ:コールドスタート時に1度だけ実行され、ウォーム呼び出しで再利用される ──
const logger = new Logger({ serviceName: "orders-worker" });
const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({})); // 接続はここで張る
const TABLE = process.env.ORDERS_TABLE; // 設定の読み出しもここで(毎回 process.env を引かない)

// ── INVOKE フェーズ:リクエストごとにここだけが走る ──
export const handler = async (
  event: SQSEvent,
  _context: Context,
): Promise<SQSBatchResponse> => {
  if (!TABLE) throw new Error("ORDERS_TABLE is not configured"); // 起動時設定の検証
  const batchItemFailures: { itemIdentifier: string }[] = [];

  for (const record of event.Records) {
    try {
      await processOrder(JSON.parse(record.body), { ddb, table: TABLE, logger });
    } catch (err) {
      // 失敗した messageId だけを再表示させる(部分バッチ失敗。第6章)
      logger.error("record processing failed", { messageId: record.messageId, err });
      batchItemFailures.push({ itemIdentifier: record.messageId });
    }
  }
  return { batchItemFailures };
};

注意:ハンドラ外の状態は「再利用されることがある」だけで、保証はされない。コールドスタートのたびにリセットされ、同時実行ごとに別環境になります。だから「グローバル変数をキャッシュ代わりに使う」のは可(高速化)でも、「グローバル変数を一意性や整合性の拠り所にする」のは不可。一意なIDやトークンはハンドラ内で都度生成します(SnapStart では特に重要——姉妹記事参照)。


2. ハンドラの作り方:薄いアダプタ+テスト容易性

ハンドラは「イベントを受け取り、ビジネスロジックに渡す薄いアダプタ」に徹します。これが SRP(単一責任)であり、テスト容易性の鍵です。

公式の標準シグネチャは言語ごとに決まっています。

// Node.js(推奨は async ハンドラ。Node.js 24 以降は callback 形式は不可)
export const handler = async (event: MyEvent, context: Context): Promise<MyResult> => { /* ... */ };
# Python(async ハンドラは不可。引数は必ず event, context の2つ)
def lambda_handler(event, context):
    ...

context には運用で効く情報が入っています。context.aws_request_id(Python)/ context.awsRequestId(Node.js)は相関IDとして全ログに通す。get_remaining_time_in_millis() / getRemainingTimeInMillis()残り時間を返すので、タイムアウト直前に安全に切り上げる制御に使えます。

2.1 ビジネスロジックは「Lambda を知らない関数」に切り出す

ハンドラ=アダプタ、ロジック=純粋関数。こう分けると、ロジックは Lambda ランタイム無しで単体テストできます(第11章)。AWS のテストガイドも「ハンドラは slim adapter にし、ビジネスロジックを分離して単体テストせよ」と推奨しています。

# domain.py — Lambda を一切 import しない純粋ロジック。単体テストが容易。
from dataclasses import dataclass

@dataclass(frozen=True)
class Order:
    id: str
    amount: int  # 最小通貨単位(整数)。金額に float を使わない

def total_with_tax(order: Order, tax_rate: float) -> int:
    if order.amount < 0:
        raise ValueError("amount must be non-negative")  # 境界で検証
    return round(order.amount * (1 + tax_rate))
# handler.py — 薄いアダプタ。境界での検証+ロジック呼び出しに専念。
import json
from domain import Order, total_with_tax

def lambda_handler(event, context):
    body = json.loads(event["body"])                 # 外部入力は境界でパース
    order = Order(id=str(body["id"]), amount=int(body["amount"]))
    return {"statusCode": 200, "body": json.dumps({"total": total_with_tax(order, 0.10)})}

3. パッケージング:ZIP / コンテナ / レイヤー

デプロイ方式は2つ、依存の共有手段が1つあります。判断軸を表で固定します。

方式サイズ上限(公式)向くケース
ZIP アーカイブ直接アップロード50MB / 解凍後250MB(レイヤー・カスタムランタイム込み)一般的な関数。最速のデプロイ。レイヤーが使える
コンテナイメージ(OCI)最大10GB大きな依存(MLライブラリ等)、独自OS/ランタイム、既存コンテナCIとの統合
レイヤー関数あたり最大5個/opt に展開、解凍後250MBの枠を共有共通依存・共通ユーティリティをZIP関数群で共有

実務の指針:

  • まずは ZIP。デプロイが速く、レイヤーで共通依存を切り出せる。250MBの解凍後上限に当たったらコンテナへ。
  • コンテナは「大きい・特殊・既存資産」のとき。10GBまで積めるが、コールドスタートと運用は重くなりがち。レイヤーは使えない(依存はイメージに同梱)。
  • Go / Rust ではレイヤー非推奨(公式)。実行ファイルに依存を同梱した方がコールドスタートに有利。

アンチパターンnode_modules を丸ごと固める。AWS SDK v3 は必要なサブクライアントだけ import し、不要な依存を削るとパッケージが小さくなり、ダウンロード=コールドスタートが速くなります。バンドラ(esbuild 等)でツリーシェイクするのが定石です。


4. 同時実行とスケール:予約・プロビジョンド・スロットリング

Lambda の「スケール」を数字で理解します。

  • 同時実行数(concurrency)=同時に処理中のリクエスト数。1リクエストにつき実行環境1つ。
  • リトルの法則同時実行数 = 平均リクエスト/秒 × 平均処理時間(秒)。例:100 req/s × 0.5s = 50。これが必要な同時実行数の見積もり式。
  • アカウント既定の同時実行上限は1,000(リージョン単位、引き上げ申請可)。さらにRPS上限はアカウント同時実行の10倍(既定なら10,000 RPS)——処理が数十msと短い関数で効いてきます。
  • スケール速度は「1関数あたり10秒で1,000環境ずつ」。各関数が独立してこの速度でバーストできる(リージョン共有の旧バースト枠は撤廃済み)。

同時実行の制御レバーは2つあります。混同しないよう表で固定します。

レバー何をするか課金主な用途
予約済み同時実行(Reserved)関数の同時実行に上限と下限を設定。他関数はその枠を使えない追加課金なし(ただしアカウント枠を消費)下流(RDS等)の保護、暴走の封じ込め、0で緊急停止(キルスイッチ)
プロビジョンド同時実行(Provisioned)環境を事前に初期化しておきコールドスタートを消す追加課金あり二桁ミリ秒の応答が必須のレイテンシ重視API

スロットリング:同時実行(または10倍のRPS)上限を超えると、同期呼び出しは HTTP 429(TooManyRequestsException を返します。予約済み同時実行 = 0 にすると全リクエストを 429 で弾くので、インシデント時のキルスイッチとして使えます。非同期・イベントソースはスロットル時に内部キューで保持・再試行されます(第6章)。

プロビジョンド同時実行・SnapStart・コールドスタートの使い分けと費用対効果は、これだけで一本の記事になります。Lambda コールドスタート最適化ガイド に詳細を分離しました。


5. 呼び出しモデルと失敗の扱い:sync / async / イベントソース

「誰がリトライするのか」は呼び出しモデルで決まります。ここを取り違えると、失敗が静かに消える永遠に詰まるかのどちらかになります。

モデルリトライの主体
同期(RequestResponse)API Gateway、Function URL、直接 InvokeLambda は自動リトライしない。呼び出し側が判断
非同期(Event)S3通知、SNS、EventBridge ルールLambda が内部キューで再試行(既定2回・計3回)
イベントソースマッピングSQS、Kinesis、DynamoDB StreamsLambda がポーリングして同期起動。再試行はソース仕様に従う

5.1 非同期呼び出し:既定2回リトライ、証跡は Destinations で受ける

非同期呼び出しは内部キューに入り、関数エラー時に**既定で2回再試行(計3回)**します(1回目まで1分、2回目まで2分待つ)。制御パラメータは2つ:

  • MaximumRetryAttempts0〜2(既定2)。
  • MaximumEventAgeInSeconds60〜21600(=最大6時間)。古すぎるイベントは捨てる。

失敗イベントの行き先は、旧来のDLQ(SQS/SNSのみ)ではなく On-failure Destinations を推奨します。Destinations は **SQS / SNS / Lambda / EventBridge(失敗時はS3も)**を宛先にでき、関数のレスポンス詳細も記録されます。成功時の宛先(on-success)も指定できます。

# Terraform: 非同期呼び出しのリトライ上限・イベント寿命・失敗時の宛先
resource "aws_lambda_function_event_invoke_config" "orders" {
  function_name                = aws_lambda_function.orders.function_name
  maximum_retry_attempts       = 2      # 0〜2(既定2)
  maximum_event_age_in_seconds = 3600   # 60〜21600。1時間より古い失敗は捨てる

  destination_config {
    on_failure {
      destination = aws_sqs_queue.orders_dlq.arn # 調査・再処理できる隔離先へ
    }
  }
}

5.2 イベントソース(SQS/ストリーム):部分バッチ失敗で「全部やり直し」を防ぐ

イベントソースマッピングは関数をバッチで起動します。ここで初学者が必ず踏む地雷:バッチ処理中に例外を投げると、成功済みも含めてバッチ全体が再処理される

これを防ぐのが部分バッチ失敗(partial batch response)FunctionResponseTypes=ReportBatchItemFailures を設定し、関数は失敗した ID だけbatchItemFailures に返します(第1章のTSコード参照)。SQS・Kinesis・DynamoDB Streams で共通の仕組みです。ストリームでは BisectBatchOnFunctionError(失敗時にバッチを二分割して再試行)や MaximumRetryAttempts / MaximumRecordAgeInSeconds、On-failure 宛先で「毒レコードがシャードを最大7日詰まらせる」事故を防ぎます。

SQS×Lambda の冪等consumer・可視性タイムアウト・DLQ 設計の詳細は SQS + Lambda + EventBridge で冪等な非同期処理を作る、DynamoDB Streams を起点にした CDC/イベント駆動は DynamoDB Streams × Lambda イベント駆動アーキテクチャ に、それぞれ専用記事があります。


6. 冪等性:再試行を「正常系」に変える

at-least-once の世界では、冪等性こそが信頼性の土台です。「同じイベントが2回来ても、課金は1回・在庫引当は1回」にする。これを自前で作ると、冪等性キーの条件付き挿入・TTL・進行中ロックを正しく実装する必要があり、競合状態で穴が開きがちです。

新規実装なら Powertools for AWS Lambda の冪等化ユーティリティが定石です。ペイロード(または特定フィールド)から冪等性キーを導出し、DynamoDB に処理状態を記録。進行中は INPROGRESS レコードでロックし、並行する重複呼び出しを弾く。完了後は結果をキャッシュして返します。

# Python: Powertools の冪等化。デコレータ1つで「2回来ても1回」にする。
from aws_lambda_powertools.utilities.idempotency import (
    DynamoDBPersistenceLayer, idempotent_function, IdempotencyConfig,
)

persistence = DynamoDBPersistenceLayer(table_name="idempotency")
# 全ペイロードではなく注文IDだけを冪等性キーにする(再送で payload が微妙に変わっても同一視)
config = IdempotencyConfig(event_key_jmespath="id", expires_after_seconds=3600)

@idempotent_function(data_keyword_argument="order", persistence_store=persistence, config=config)
def charge(order: dict) -> dict:
    # ここが2回呼ばれても、課金は1回しか実行されない
    return run_charge(order)
// TypeScript: @aws-lambda-powertools/idempotency(peer依存に @aws-sdk/client-dynamodb と lib-dynamodb)
import { makeIdempotent } from "@aws-lambda-powertools/idempotency";
import { DynamoDBPersistenceLayer } from "@aws-lambda-powertools/idempotency/dynamodb";

const persistenceStore = new DynamoDBPersistenceLayer({ tableName: "idempotency" });
export const handler = makeIdempotent(async (event: { id: string }) => runCharge(event), {
  persistenceStore,
});

設計の勘所:冪等性キーは「同じ業務操作なら同じ値」になるよう選ぶ(注文ID・請求期間など)。全ペイロードをキーにすると、リトライ時にタイムスタンプ等が混ざって別物と誤認します。TTL(既定3600秒)は「再送が来うる窓」より長く。私が決済プラットフォームで二重課金0件を達成できたのは、この冪等性キー設計を業務の不変条件に合わせたからです。冪等化の理論的背景は 冪等な決済設計(二重課金対策) も参照ください。


7. 可観測性:コード変更ゼロの構造化ログ+メトリクス+トレース

「止まった処理を一目で追える」状態を作ります。Lambda は CloudWatch Logs に自動でログを送ります(実行ロールに AWSLambdaBasicExecutionRole が必要)。本番では3点セットで固めます。

  • JSON 構造化ログ+ログレベル制御(コード変更不要)。Lambda の「高度なロギング設定」で、ログ形式(Text/JSON)とアプリケーションログレベル(TRACE〜FATAL、既定INFO)を関数設定で切り替えられます(JSON形式が前提)。console.log を JSON で検索・集計可能にし、本番は INFO・調査時だけ DEBUG に上げる、をデプロイ無しで実現します。
  • Powertools の Logger / Tracer / Metrics。Logger は相関ID付きの構造化ログ、Tracer は X-Ray の薄いラッパ、Metrics は EMF(Embedded Metric Format)で標準出力にメトリクスを書き出し、CloudWatch が非同期に抽出します(PutMetricData を同期呼びしないので速くて安い)。
  • X-Ray アクティブトレーシングActive にするとサンプリングされたリクエストのトレースを自動生成。xray:PutTraceSegments 等の権限(AWSXRayDaemonWriteAccess)が要ります。
# Powertools: 構造化ログ・トレース・EMFメトリクスを最小コードで
from aws_lambda_powertools import Logger, Tracer, Metrics
from aws_lambda_powertools.metrics import MetricUnit

logger = Logger(service="orders")     # JSON構造化ログ+相関ID
tracer = Tracer(service="orders")     # X-Ray セグメント
metrics = Metrics(namespace="Orders") # EMFでCloudWatchメトリクス(同期API呼び出し不要)

@metrics.log_metrics            # 集計したメトリクスをフラッシュ
@tracer.capture_lambda_handler  # ハンドラをトレース
@logger.inject_lambda_context   # request_id等を全ログに付与
def lambda_handler(event, context):
    metrics.add_metric(name="OrdersProcessed", unit=MetricUnit.Count, value=1)
    logger.info("processing order", extra={"order_id": event.get("id")})
    return {"ok": True}

アラートは症状で鳴らすErrors / Throttles / Duration(P99) / ConcurrentExecutions / Destinations の失敗キュー件数(1件で即通知)。Lambda Insights(拡張レイヤー)を足すと、CPU・メモリ・コールドスタートまで1呼び出し1イベントで取れます。可観測性の体系は OpenTelemetryで本番の可観測性を作る を参照。


8. セキュリティ:最小権限・秘密情報・VPC・公開エンドポイント

Lambda のセキュリティは「2つのポリシー」を分けて理解するところから始まります。

  • 実行ロール(execution role):関数がassume する IAM ロール。AWSサービスへのアクセス権はここ。最小権限で。まずは AWSLambdaBasicExecutionRole(ログ権限のみ)から始め、必要な操作だけ足す。IAM Access Analyzer で CloudTrail の利用実績からポリシーを生成するのが安全。
  • リソースベースポリシー誰がこの関数を呼べるか。AWSサービスが起動する場合はこちらだけが評価されます。
// 実行ロールの最小権限例:この関数が触る1テーブルへの必要操作のみ。ワイルドカード '*' を避ける
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["dynamodb:PutItem", "dynamodb:GetItem"],
    "Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/orders"
  }]
}

秘密情報:環境変数は KMS で保存時暗号化されます(既定は AWS マネージドキー、要件次第で CMK)。ただしAPI キーやDB資格情報を環境変数に平文で置くのは非推奨。公式の指針は Secrets Manager / SSM Parameter Store に置き、AWS Parameters and Secrets Lambda Extension で取得・キャッシュ(既定TTL 300秒)すること。アプリは「拡張のローカルエンドポイントから読む」だけになり、ローテーションにも追従できます。

VPC:プライベートな RDS 等へは Lambda を VPC にアタッチして接続します。外向き通信には NAT ゲートウェイが必要(プライベートサブネット配置だけではインターネットに出られない)。Lambda が作る ENI は Hyperplane ENI で、同じサブネット+セキュリティグループの関数間で共有・再利用されるため、VPC でも高速にスケールします。AWSサービスへは VPC エンドポイントで NAT を介さず到達できます。

Function URL:関数に直結する HTTPS エンドポイント。認証は AWS_IAMNONE公開API以外は AWS_IAM を選ぶNONE(公開)にするなら、最低限 WAF・レート制限(予約済み同時実行)・lambda:InvokedViaFunctionUrl 条件キーで締める。2025年10月以降、新規 Function URL は lambda:InvokeFunctionUrllambda:InvokeFunction の両権限を要します。


9. コスト最適化:請求書の式を理解し、速さで安くする

Lambda の料金は2要素です。式が分かれば請求書が読めます。

月額 ≒ リクエスト課金 + 実行時間課金
  リクエスト課金 = 総リクエスト数 × $0.20 / 100万
  実行時間課金   = 割当メモリ(GB) × 実行時間(秒, 1ms単位で切り上げ) × 単価(GB-秒)
  • x86 の実行時間単価は約 $0.0000166667 / GB-秒(第1ティア・US East基準)。Arm64(Graviton2)は実行料金が x86 比20%安い。互換性があるなら Arm64 が基本的に有利。
  • 無料利用枠:月100万リクエスト+40万 GB-秒。
  • 実行時間は1ms単位で切り上げ/tmp を512MB超にする・プロビジョンド同時実行を使う、は別課金。
  • 2025年8月から INIT 時間も課金対象(マネージドランタイム+ZIPのオンデマンド関数も対象に統一)。重い初期化はコストにも乗る。

9.1 メモリ調整は「速さ=安さ」の単一ノブ

CPU はメモリに比例配分され、1,769MB で1 vCPU 相当。つまりメモリを上げると CPU も増え、CPUバウンドな処理は短時間化してトータルコストが下がることがよくあります(128MBで遅く回すより1024MBで速く終える方が安い、という逆転が起きる)。メモリは推測せず計測して決めるのが鉄則です。AWS Lambda Power Tuning(公式サンプル)でコスト最小点を探します。

安くする手効き方
Arm64 に切り替え実行料金20%減。多くのランタイムでビルドし直すだけ
メモリを計測で最適化CPUバウンドは増メモリで短時間化→総額減のことが多い
パッケージを小さくコールドスタート短縮=INIT課金とレイテンシ減
接続をハンドラ外で再利用ウォーム呼び出しの実行時間短縮
不要な同期待ちを消す外部API待ちの間も課金される。並行化・非同期化

10. テスト容易性:ロジックは手元で、結合はクラウドで

Lambda のテストは2層で考えます。

  • 単体テスト:ハンドラを薄く保ち(第2章)、ビジネスロジックは Lambda 非依存の純粋関数として普通の単体テストで回す。context はモックでよい。最速・最安・最も多くのバグをここで捕まえる。
  • 結合テスト:AWS は**「クラウドでのテストを優先せよ」と明言しています。エミュレータ(sam local invoke / start-api、LocalStack 等)は速い反面、IAM・サービス設定・クォータ・API差分を再現しきれず「手元では通るがクラウドで落ちる」を生む。エミュレータは控えめに**使い、本物のサービスに対する結合・E2E をクラウドで回すのが公式の推奨です。
# 単体テスト:純粋ロジックは Lambda 無しで即テストできる(第2章の domain.py)
import pytest
from domain import Order, total_with_tax

def test_total_with_tax_rounds_half_up():
    assert total_with_tax(Order(id="o1", amount=1000), 0.10) == 1100

def test_negative_amount_rejected():
    with pytest.raises(ValueError):
        total_with_tax(Order(id="o2", amount=-1), 0.10)
# 結合の入口:手元で1度だけ叩く(Docker必須)。本格的な検証はクラウドにデプロイして行う
sam local invoke OrdersFunction --event events/order.json

11. まとめ:本番Lambdaチートシート

最後に、迷ったときの早見表です。

  • 実行モデル:Init→Invoke→Shutdown。接続・SDKクライアントはハンドラ外で1度だけ。一意なIDはハンドラ内で都度生成。
  • ハンドラ:薄いアダプタ。ビジネスロジックはLambda非依存の純粋関数に切り出してテストする。
  • パッケージ:まずZIP+レイヤー、250MB超でコンテナ。node_modules丸ごとはNG、ツリーシェイクする。
  • スケール:必要同時実行=RPS×処理秒。下流保護は予約済み、レイテンシ保証はプロビジョンド、予約=0で緊急停止。
  • 失敗設計:同期は自動リトライ無し。非同期は既定2回+On-failure Destinations。イベントソースは部分バッチ失敗で全件やり直しを防ぐ。
  • 冪等性:再試行は仕様。Powertoolsの冪等化+業務に沿った冪等性キー+TTL。
  • 可観測性:JSON構造化ログ+ログレベル制御(コード変更ゼロ)、Powertools Metrics(EMF)、X-Ray。症状でアラート。
  • セキュリティ:実行ロールは最小権限。秘密はSecrets Manager+拡張でキャッシュ。VPCはNAT/エンドポイント。Function URLは原則AWS_IAM
  • コストメモリ×時間(1ms)+リクエストArm64で20%減、メモリは計測で最適化、INITも課金される。

Lambda は「サーバーレスだから楽」ではなく、at-least-once・コールドスタート・最小権限・課金の式という制約の上で、冪等性・可観測性・コストを設計する仕事です。私は環境分野のマルチテナント決済プラットフォームで、月次一括課金・CO2集計を冪等・自動再処理・最小権限・症状ベースのアラートで固め、本番稼働中の二重課金・残高不整合 0件を達成しました。

「自社のこのワークロードを、Lambda で速く・安く・落ちても自動で立ち直る形にしたい」——その設計から実装・運用・コスト最適化まで、一人 × 生成AI(Claude Code)の速さで一気通貫に伴走します。 計算基盤の選定段階(Lambda か Fargate か)からでも、お気軽にご相談ください。


参考(公式ドキュメント)

友田

友田 陽大

وزیر (METI) ایوارڈ یافتہ پروڈکٹ کے ڈویلپر۔ TypeScript + Python + AWS کے ساتھ میں SaaS، صنعتی ڈیجیٹل تبدیلی اور پروڈکشن کے قابل جنریٹو اے آئی (RAG) تنہا ابتدا سے انتہا تک فراہم کرتا ہوں — تقاضوں کی تعیین سے انفراسٹرکچر اور آپریشن تک۔

Got a challenge?

From design to implementation and operations — solo × generative AI

Implementation like this article's, end to end from requirements to production. Start with a free 30-minute technical consult and tell me about your situation.

پروجیکٹ کی بنیاد پر کام اور تکنیکی مشاورت دونوں کے لیے دستیاب ہوں۔ 30 منٹ کی مفت مشاورت سے آغاز کریں۔

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

یہ بھی پڑھنے کے قابل