# LambdaからRDS/Auroraに繋ぐ：接続枯渇を防ぐRDS Proxy・Data API・VPC設計とコスト最適化

> AWS LambdaからRDS/Aurora（PostgreSQL/MySQL）に本番品質で接続する実装ガイド。同時実行のファンアウトによる接続枯渇という根本問題、RDS Proxyの接続プールとピン留め回避、接続不要なRDS Data API、IAMデータベース認証、VPC/NATコストとPrivateLink、Aurora Serverless v2のスケールトゥゼロまで、AWS公式仕様に忠実な実コードで解説します。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: AWS, Lambda, RDS, Aurora, サーバーレス
- URL: https://tomodahinata.com/blog/aws-lambda-rds-aurora-connection-management-rds-proxy-vpc-guide

## 要点

- Lambda×RDBの根本問題は接続枯渇：同時実行ごとに別の実行環境が別々の接続を開き、数千同時実行がRDSの有限なmax_connectionsを食い尽くす
- ハンドラ外で接続を張る再利用は『ウォーム環境1つにつき1接続』までで、ファンアウトは解決しない。本番はRDS Proxyで接続をプール・共有する
- RDS Proxyの天敵はピン留め（pinning）。SET・一時テーブル・セッションレベルの advisory lock等でクライアントとDB接続が固定され多重化が効かなくなる
- 接続管理そのものを無くすならRDS Data API：HTTPでSQLを実行、永続接続もVPCも不要。Aurora PostgreSQL/MySQLのServerless v2＋プロビジョンドで利用可
- コスト：VPCのLambdaが外部に出るにはNAT（時間＋GB課金）。Secrets ManagerはPrivateLinkでNAT回避。Aurora Serverless v2は最小0 ACUで自動ポーズ可

---

「Lambda から普通に PostgreSQL に繋いだら、アクセスが増えた瞬間に `too many connections` でDBが落ちた」——サーバーレスと従来型リレーショナルDBの組み合わせで、**必ず最初にぶつかる壁**です。Lambda は秒間で数百・数千の実行環境までスケールしますが、**RDS/Aurora の同時接続数は有限**。この2つの世界観の衝突を設計で吸収しないと、本番は接続枯渇で止まります。

この記事は、AWS Lambda から **RDS / Aurora（PostgreSQL・MySQL）**へ**本番品質で接続する**ための実装ガイドです。**接続枯渇という根本問題**から、**RDS Proxy**・**Data API**・**IAM認証**・**VPC/NATコスト**・**Aurora Serverless v2**までを一気通貫で解説します。題材として、B2B SaaS（[木材流通業界のDX](/case-studies/lumber-industry-dx)）をPostgreSQL上で本番運用する中で得た接続管理の知見も交えます。Lambda 本体の実行モデルは姉妹記事 [AWS Lambda 本番運用ガイド](/blog/aws-lambda-production-guide) に委ね、本稿は**「リレーショナルDBへの接続」一点**に集中します。

> **この記事のルール**：仕様・パラメータ名・制限は **AWS 公式ドキュメント（2026年6月時点）** に基づきます。料金（RDS Proxy・NAT等）はリージョン・時期で変わるため、本稿では具体額を断定せず**課金モデル**を示します。本番投入前に必ず公式（末尾「参考」）で最新値・最新料金を確認してください。

---

## 0. メンタルモデル：Lambdaは「接続を共有しない」前提で動く

最初に、なぜ難しいのかを1枚に固定します。

- **同時実行 = 別々の実行環境 = 別々のDB接続**。Lambdaは1つの同時リクエストごとに独立した実行環境を割り当てる。それぞれが**自分専用のDB接続**を開く。
- **Lambdaは数千までスケール、RDSの `max_connections` は有限**。例えば1,000同時実行が各1接続を開けば、DBは1,000接続を要求される。これが**接続枯渇（connection exhaustion）**。
- **ハンドラ外の接続再利用は「ウォーム環境1つにつき1接続」まで**。これはレイテンシ短縮に効くが、**同時実行のファンアウトそのものは解決しない**（環境が1,000個あれば接続も最大1,000）。
- **だから本番は「接続を共有する層（RDS Proxy）」か「接続を持たない方式（Data API）」を選ぶ**。これが本記事の二択です。

公式も明言します——「**直接接続は単純なケースで有用、本番ではプロキシを推奨**。データベースプロキシは共有接続のプールを管理し、関数がDB接続を枯渇させずに高い同時実行に到達できるようにする」。

---

## 1. まず土台：ハンドラ外で接続し、アイドル切断に備える

RDS Proxy や Data API に進む前に、**どの方式でも効く基本**を押さえます。接続は**ハンドラ外で1度だけ**張り、ウォーム呼び出しで再利用します（公式のベストプラクティス）。

```ts
// プールはハンドラ外（INIT）で生成。ウォーム環境内で再利用される。
import { Pool } from "pg";

// 1環境あたり小さなプール。max=1〜数。大きくしても同時実行のファンアウトは別問題
const pool = new Pool({
  host: process.env.DB_HOST,
  max: 1,                       // Lambdaは並列処理しない（1呼び出し1処理）ので小さく
  idleTimeoutMillis: 0,         // Lambda側で勝手に切らない（下のkeep-aliveと併用）
  keepAlive: true,              // アイドル接続の切断対策
});

export const handler = async (event: { id: string }) => {
  // pool.query は同一環境で接続を使い回す（再接続コストを払わない）
  const { rows } = await pool.query("SELECT id, total FROM orders WHERE id = $1", [event.id]);
  return rows[0] ?? null;
};
```

> **公式の注意**：Lambda は**アイドル接続を時間とともに破棄**する。破棄済みの接続を再利用しようとすると接続エラーになるため、**keep-alive** を有効化し、クエリ前に死活を確認できる設計にします。ただし繰り返しになりますが、**これは「環境内再利用」**であって、**同時実行が増えれば接続数も増える**——次章のプール層が要る理由です。

---

## 2. 本命：Amazon RDS Proxy で接続をプール・共有する

**RDS Proxy** は、Lambda 群とDBの間に立つ**フルマネージドの接続プール**です。多数のクライアント接続を**少数のDB接続に多重化（multiplex）**し、DBの接続枯渇を防ぎます。フェイルオーバー時も接続を保持して回復性を上げます。

### 2.1 何が嬉しいか

- **接続のプール・共有**：`MaxConnectionsPercent`（DBの `max_connections` に対する割合）でDB側接続の上限を制御。Lambdaが何千スケールしても、DBへの接続は**プールの範囲に収まる**。
- **IAM認証 ＋ Secrets Manager**：クライアント（Lambda）は**IAMで認証**、プロキシはDBへ**Secrets Manager の資格情報 or IAM DB認証**で接続。**コードにDBパスワードを持たない**。
- **対応エンジン**：Aurora（MySQL/PostgreSQL）、RDS for PostgreSQL / MySQL / MariaDB / SQL Server。

```ts
// RDS Proxy 経由：接続先をプロキシのエンドポイントにするだけ。IAM認証トークンでパスワードレス
import { Signer } from "@aws-sdk/rds-signer";
import { Pool } from "pg";

const signer = new Signer({
  hostname: process.env.PROXY_HOST!, // RDS Proxy のエンドポイント
  port: 5432,
  username: process.env.DB_USER!,
  region: process.env.AWS_REGION!,
});

// 認証トークンは15分で失効するため、接続のたびに発行する（password を関数化）
const pool = new Pool({
  host: process.env.PROXY_HOST,
  user: process.env.DB_USER,
  password: () => signer.getAuthToken(), // ← パスワードの代わりにIAMトークン
  ssl: { rejectUnauthorized: true },
  max: 1,
});

export const handler = async () => (await pool.query("SELECT now()")).rows[0];
```

### 2.2 RDS Proxy の天敵：ピン留め（pinning）

ここが本番で一番ハマる点です。プロキシは**接続を多重化**しますが、**セッション状態に依存する操作**を検知すると、その**クライアント接続を特定のDB接続に固定（pinning）**します。固定された接続は**他のクライアントが再利用できなくなり、多重化の効果が消えます**。

公式が挙げる主なピン留めトリガー：

| エンジン共通 | PostgreSQL の例 | MySQL の例 |
| --- | --- | --- |
| 16KB超のSQL文 | `SET`（変数設定）、`PREPARE`/`DEALLOCATE`/`EXECUTE`、一時テーブル/シーケンス/ビュー作成、カーソル宣言、`LISTEN`、**セッションレベルの advisory lock**（`pg_advisory_lock`） | テーブルロック、`GET_LOCK`、ユーザー変数設定、一時テーブル作成、プリペアドステートメント |

回避の指針（公式）：

- **不要なセッション状態変更を避ける**。毎接続で同じ初期化をするなら、**プロキシの初期化クエリ**にまとめる（各クエリで `SET` しない）。
- **PostgreSQLの advisory lock はセッションレベル（`pg_advisory_lock`）でピン留めされるが、トランザクションレベル（`pg_advisory_xact_lock`）はされない**。冪等化・排他制御でロックを使うなら**トランザクションレベルを選ぶ**。
- **`DatabaseConnectionsCurrentlySessionPinned` メトリクスを監視**。ピン留めが多ければ、上のトリガーを潰す。

> **料金モデル**：RDS Proxy は**プロビジョンドDBではvCPU時間あたり**（Aurora ServerlessではACU時間あたり）課金で、課金状態変更後は**最低10分**の課金。具体額はリージョン・時期で変わるため[公式の料金ページ](https://aws.amazon.com/rds/proxy/pricing/)で確認してください。**「常時少しのトラフィックでも接続を頻繁に開閉する」Lambdaワークロードほど、Proxyの費用対効果が高い**のが目安です。

---

## 3. もう一つの解：RDS Data API で「接続を持たない」

接続管理そのものを無くす選択肢が **RDS Data API** です。**HTTPのエンドポイントにSDKでSQLを送る**方式で、**永続接続が不要**。Lambda を**VPCに入れなくてもDBにアクセスできる**（プロキシやENIの設計から解放される）のが大きな利点です。

```ts
// Data API：接続プールもVPCも不要。SDKでSQLをHTTP実行。認証はIAM＋Secrets Manager
import { RDSDataClient, ExecuteStatementCommand } from "@aws-sdk/client-rds-data";

const rds = new RDSDataClient({}); // 永続接続なし。ハンドラ外で1度だけ生成

export const handler = async (event: { id: string }) => {
  const res = await rds.send(new ExecuteStatementCommand({
    resourceArn: process.env.CLUSTER_ARN,   // Auroraクラスタ
    secretArn: process.env.SECRET_ARN,       // DB資格情報（Secrets Manager）。コードに持たない
    database: "app",
    sql: "SELECT id, total FROM orders WHERE id = :id",
    parameters: [{ name: "id", value: { stringValue: event.id } }], // パラメータ化でSQLi対策
  }));
  return res.records ?? [];
};
```

公式仕様と制限：

- **対応**：Aurora PostgreSQL（Serverless v2 ＋ プロビジョンド、13.11/14.8/15.3/16.1/17.4 以降）、Aurora MySQL（3.07 以降）。**ライター（書き込み）インスタンスでのみ**実行可、Tクラスは非対応。
- **認証**：IAM ＋ Secrets Manager。**呼び出しに資格情報を渡さない**（Secrets Managerが真実源）。
- **制限**：**レスポンスは1 MiB上限**（超えると打ち切り）。大量行の取得には不向き。レイテンシのオーバーヘッドもあるため、**短いトランザクション・少量結果**に向く。

### 3.1 RDS Proxy か Data API か

| 観点 | RDS Proxy | Data API |
| --- | --- | --- |
| 接続管理 | プールを共有（接続はある） | **接続なし**（HTTP） |
| VPC | 必要（同一VPC） | **不要** |
| 大量結果・ストリーミング | 得意 | 1 MiB上限で不向き |
| 既存のドライバ/ORM | そのまま使える | SDK/専用ドライバが必要 |
| 向くワークロード | 一般的なOLTP、既存資産 | 軽量クエリ、VPCを避けたい、最小構成 |

迷ったら：**既存のORM/ドライバ資産があり、まとまった結果を扱う**なら RDS Proxy。**新規で軽量・VPCの複雑さを避けたい**なら Data API（Aurora限定）。

---

## 4. VPC とネットワーク：繋がるが「外に出られない」罠とコスト

LambdaからRDSに繋ぐには、**RDSと同じVPC**にLambdaを置きます（Proxy/直接接続の場合）。ここで2つの落とし穴。

- **VPCに入れると、既定でインターネットに出られなくなる**。公式明言：「VPCにアタッチするとそのVPC内のリソースしかアクセスできない」「**パブリックサブネットに置いてもインターネットアクセスは得られない**」。Secrets Manager のパブリックエンドポイントや外部APIに出るには **NATゲートウェイ**が要る。
- **NATは時間課金＋データ処理（GB）課金**。常時稼働でじわじわ効く。**Secrets Manager などAWSサービスへは VPCインターフェースエンドポイント（PrivateLink）でNATを回避**できる——レイテンシ・コスト・セキュリティの全てで有利。

```text
[Lambda(私有サブネット)] --(同一VPC)--> [RDS Proxy] --> [Aurora]
        |
        +--(PrivateLink/VPCエンドポイント)--> [Secrets Manager]   ← NATを使わない
        |
        +--(NATゲートウェイ:時間＋GB課金)----> [外部API/パブリックEP] ← 必要な時だけ
```

> Hyperplane ENI（VPC関数のネットワーク基盤）はサブネット＋SGの組み合わせ単位で共有・再利用され、各65,000接続を捌きます。VPCのコールドスタートが「今は速い」理由と設計の詳細は [コールドスタート最適化ガイドのVPC章](/blog/aws-lambda-cold-start-snapstart-provisioned-concurrency-performance-guide) に分離しました。

### 4.1 認証：IAM DB認証という選択

DBの資格情報管理には、Secrets Manager のほかに **IAMデータベース認証**があります。**パスワード不要**で、**SigV4で生成した15分有効の認証トークン**で接続。`MySQL`/`MariaDB`/`PostgreSQL` 対応。ただし公式は「**毎秒200新規接続未満**で使うこと、それ以上は接続プーリング/RDS Proxyを使え」と推奨。**高頻度の新規接続ではRDS Proxyに寄せる**のが正解です。

---

## 5. どのDBを選ぶか：Aurora Serverless v2 の相性

「サーバーレスのスパイクするLambda」に対して、**容量を自動で伸縮するDB**が噛み合います。**Aurora Serverless v2** は **ACU（≈2GiBメモリ）単位で秒刻みに自動スケール**し、**最小0 ACU（自動ポーズ）**まで絞れます。

- **スケールトゥゼロ（2024年〜）**：最小ACUを `0` にすると、ユーザー接続が無い間は**ポーズして容量課金が0**になり、**接続が来ると自動再開**（典型15秒・アイドルタイムアウトは5分〜1日）。**間欠的なLambda負荷とコスト効率が噛み合う**。
- **重要な両立不可**：**RDS Proxy を関連付けると、プロキシが接続を維持し続けるためインスタンスは自動ポーズしない**。「Proxyで接続枯渇を防ぐ」か「スケールトゥゼロで休止中コストを消す」かは、**ワークロードで選ぶトレードオフ**です。

> NoSQL（DynamoDB）の方が素直にサーバーレスと噛み合う場面も多いです。リレーショナルが本当に要るのか（結合・トランザクション・既存スキーマ）を含めた選定は [DynamoDB vs RDS/Aurora 選定ガイド](/blog/dynamodb-vs-rds-aurora-postgresql-when-to-use-nosql-decision-guide)、接続プーリングの一般論は [PgBouncerによるサーバーレス接続プーリング](/blog/postgresql-connection-pooling-pgbouncer-serverless-guide) を参照してください。

---

## 6. まとめ：Lambda × リレーショナルDB チートシート

- **根本問題**：同時実行ごとに別接続。**Lambdaは数千スケール、RDSの `max_connections` は有限** → 接続枯渇。
- **基本**：接続/プールは**ハンドラ外**で1度だけ、**keep-alive**でアイドル切断に備える。ただし**ファンアウトは解決しない**。
- **本命=RDS Proxy**：接続をプール・共有、**IAM認証＋Secrets Manager でパスワードレス**。天敵は**ピン留め**——`SET`・一時テーブル・**セッションレベルadvisory lock**を避け、初期化はプロキシのinitクエリへ、`…SessionPinned` を監視。
- **接続を持たない=Data API**：HTTPでSQL、**VPC不要**、Aurora限定、**レスポンス1 MiB上限**。軽量クエリ向き。
- **VPCコスト**：私有サブセットのLambdaが外に出るには**NAT（時間＋GB）**。AWSサービスは**PrivateLinkでNAT回避**。認証は高頻度なら**Secrets Manager/RDS Proxy**、低頻度なら**IAM DB認証**。
- **DB選定**：**Aurora Serverless v2 はスケールトゥゼロ**でスパイク負荷と好相性。ただし**RDS Proxy併用時は自動ポーズしない**。

私はB2B SaaSをPostgreSQL上で本番運用する中で、「Lambda/コンテナの同時実行 × 有限なDB接続」という制約に何度も向き合ってきました。**接続をプール層で吸収し、秘密情報をコードから排し、NATコストをエンドポイントで削る**——この設計規律が、DBを落とさず・安全に・安く運用する土台です。

**「自社のサーバーレスがDB接続で詰まる/落ちる、コストが読めない」——接続枯渇の解消からRDS Proxy/Data APIの選定、VPCコスト最適化まで、一人 × 生成AI（Claude Code）の速さで伴走します。** 現状の接続設計の診断からでも、お気軽にご相談ください。

---

### 参考（公式ドキュメント）

- [Using Amazon RDS with Lambda](https://docs.aws.amazon.com/lambda/latest/dg/services-rds.html) — 直接接続 vs プロキシ、RDS Proxy推奨
- [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html) — 接続プール、IAM認証、対応エンジン
- [Avoiding pinning (RDS Proxy)](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-pinning.html) — ピン留めのトリガーと回避、`DatabaseConnectionsCurrentlySessionPinned`
- [RDS Proxy connections / MaxConnectionsPercent](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-connections.html) — `max_connections` に対する上限制御
- [Using RDS Data API](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) / [limitations](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.limitations.html) — 接続不要、IAM＋Secrets Manager、1 MiB上限
- [IAM database authentication](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html) — 15分トークン、毎秒200接続の目安
- [Lambda networking / VPC](https://docs.aws.amazon.com/lambda/latest/dg/foundation-networking.html) — VPC内は既定で非インターネット、NATの必要性
- [Secrets Manager VPC endpoints (PrivateLink)](https://docs.aws.amazon.com/secretsmanager/latest/userguide/vpc-endpoint-overview.html) — NAT回避
- [Aurora Serverless v2 auto-pause / scale to zero](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2-auto-pause.html) — 最小0 ACU、RDS Proxy併用時は非ポーズ
- [Amazon RDS Proxy pricing](https://aws.amazon.com/rds/proxy/pricing/) — vCPU時間/ACU時間あたりの課金モデル
