Lambda関数からRDSに接続するたびに「Too many connections」エラーが出て困った経験はないだろうか。オンプレでアプリケーションサーバーを数台運用していたときは気にならなかったDB接続数が、サーバーレス移行後に突然ボトルネックになるのは、クラウド移行あるあるの落とし穴だ。
原因はシンプルで、Lambdaは同時実行数に応じて関数インスタンスが増殖し、それぞれが独立してDBコネクションを開く。1,000同時実行なら1,000本のコネクションが同時にRDSに押し寄せる。これはオンプレのコネクションプールとはまったく異なる挙動だ。
この問題を解消するのが Amazon RDS Proxy だ。この記事では、RDS Proxyの仕組みとアーキテクチャ、設定手順、Lambda連携時の実践パターン、料金の読み解き方、現場でハマりがちなPinning問題まで、実務で使える知識を体系的に解説する。

なぜLambdaとRDSの組み合わせで問題が起きるのか
オンプレではアプリケーションサーバーを数台立て、各サーバーにコネクションプール(PgBouncer、HikariCPなど)を設置し、DBへの接続数を「サーバー台数×プールサイズ」の範囲に収める設計が一般的だった。この構成では、DBコネクション数は最大でも数十本程度に収まる。
Lambda関数はコードが実行されるたびに新しい実行環境(コンテナ)が起動し、各実行環境がDBに対して直接コネクションを張る。同時実行数が100を超えると、DBはその分のコネクション確立要求を受け付けなければならない。しかも、Lambda実行環境の生成・廃棄タイミングはLambdaが制御するため、コネクションのライフサイクルが不安定になりやすい。
RDSのコネクション上限はインスタンスタイプによって決まる。db.t3.mediumでは約400本、db.r6g.largeでは約1,200本だ(2026年8月時点の参考値。実際の値はmax_connectionsパラメータをParameter Groupで確認すること)。Lambdaの同時実行数がこの上限に近づくと、コネクション確立に失敗して「Too many connections」エラーが多発する。
RDS Proxyの仕組みとアーキテクチャ
RDS Proxyは、アプリケーション(Lambda関数等)とRDSの間に挟まる マネージドデータベースプロキシ だ。アプリケーションはProxyのエンドポイントに接続し、ProxyがDB本体との接続を管理する。
1. コネクションプーリング
RDS Proxyはクライアント(Lambda)からの接続要求を受け、DB本体への接続を使い回す。Lambdaが1,000同時実行していても、Proxy → RDB間の接続数はProxyが適切に制御して大幅に削減できる。このコネクションの「多重化」がRDS Proxyの中核機能だ。
コネクション確立のオーバーヘッドはTCP 3-wayハンドシェイク+TLSネゴシエーションで数十~数百ミリ秒かかる。プーリングにより既存の接続を再利用できるため、クエリレイテンシの改善にもつながる。
2. ピン留め(Pinning)に注意
RDS Proxyがコネクションを正しく多重化するには、クライアントセッションの状態をProxyが把握できなければならない。しかし、以下の操作を実行するとProxyはクライアントとDBコネクションを1対1で固定(ピン留め)してしまい、多重化の恩恵が得られなくなる。
・セッション変数の変更(SET文による変数設定)
・トランザクション外のプリペアドステートメント
・ラージオブジェクト(BYTEA等)の操作(PostgreSQL)
・一時テーブルの作成
Pinningが多発するとコネクション多重化率が下がり、RDS Proxyの導入効果が薄れる。CloudWatchの DatabaseConnectionsCurrentlySessionPinned メトリクスで割合を監視し、アプリケーションの実装を見直すことが重要だ。
3. フェイルオーバー時間の短縮
Multi-AZ構成のRDSでフェイルオーバーが発生すると、通常30秒~2分かかることがある。アプリケーションがRDSのDNS解決をキャッシュしていると、フェイルオーバー後の新プライマリに接続するまでのダウンタイムが伸びる。RDS Proxyを経由すると、Proxyが新プライマリへの切り替えを内部で処理するため、クライアントから見たフェイルオーバー時間が大幅に短縮される(数秒のオーダー)。
4. 対応エンジンと接続形式
・MySQL: Amazon RDS MySQL / Amazon Aurora MySQL
・PostgreSQL: Amazon RDS PostgreSQL / Amazon Aurora PostgreSQL
・MariaDB: Amazon RDS MariaDB
・SQL Server: Amazon RDS SQL Server(2023年より対応)
接続プロトコルはMySQL/PostgreSQLの標準ポートをそのまま使うため、アプリケーションの接続先エンドポイントを変えるだけで移行できる。
RDS Proxyを設定する手順
設定は「Secrets Managerに認証情報を登録 → RDS Proxyを作成 → アプリケーション(Lambda)の接続先を変更」の3ステップで完結する。
1. Secrets ManagerにDB認証情報を登録
RDS ProxyはDB認証情報をAWS Secrets Managerから取得する。コンソールまたはCLIでシークレットを作成しておく。
# AWS CLIでRDS用シークレットを作成(MySQLの例) aws secretsmanager create-secret \ --name "prod/rds/mydb" \ --secret-string '{ "username": "dbadmin", "password": "yourpassword", "engine": "mysql", "host": "mydb.xxxx.ap-northeast-1.rds.amazonaws.com", "port": 3306, "dbname": "myapp" }' \ --region ap-northeast-1
シークレットのARNはこの後のProxy作成で使用する。Secrets Managerの詳細な設定手順については、AWS Secrets Manager入門を参照してほしい。
2. RDS Proxyを作成
AWSコンソール → RDS → 「プロキシ」から「プロキシの作成」を選択する。
・プロキシ識別子: 任意の名前(例: prod-rds-proxy)
・エンジンの互換性: MySQL または PostgreSQL
・接続先: 対象のRDSインスタンスまたはAuroraクラスター
・Secrets Manager シークレット: 手順1で作成したシークレットを選択
・IAMロール: Secrets Managerへのアクセス権を持つロールを選択または作成
・VPCとサブネット: RDSと同じVPC・プライベートサブネット
作成完了まで数分かかる。完了するとProxyエンドポイント(例: prod-rds-proxy.proxy-xxxx.ap-northeast-1.rds.amazonaws.com)が払い出される。
セキュリティグループは RDSのセキュリティグループに「ProxyのSGからのインバウンドを許可するルール」 を追加することを忘れずに。ProxyのSGからRDSポート(MySQL: 3306 / PostgreSQL: 5432)への通信を許可しておく。
3. Lambda関数の接続先をProxyエンドポイントに変更
Lambda関数が接続するホスト名をRDSエンドポイントからProxyエンドポイントに書き換えるだけだ。ポート番号やDB名、認証情報はそのままで良い。
# Lambda環境変数の例(変更前) DB_HOST = mydb.xxxx.ap-northeast-1.rds.amazonaws.com # 変更後(ProxyエンドポイントをDB_HOSTに設定) DB_HOST = prod-rds-proxy.proxy-xxxx.ap-northeast-1.rds.amazonaws.com
Lambda関数はRDS ProxyのVPCと同じVPCに所属させる必要がある。LambdaのVPC設定で対象VPCのプライベートサブネットを選択し、ProxyへのアクセスをLambdaのセキュリティグループに許可しておく。
Lambda + RDS Proxyの実践設計パターン
1. 読み取り専用エンドポイントの活用
Auroraクラスターを使っている場合、RDS Proxyは リードレプリカ専用のProxyエンドポイント を作成できる。参照系クエリを読み取り専用エンドポイントに振り分けることで、プライマリの負荷を大幅に下げられる。コンソールで「エンドポイントの追加」から「リードオンリー」タイプを選択すればよい。
2. IAM認証でパスワードレス接続
RDS ProxyはIAM認証に対応しており、データベースパスワードを使わずに接続できる。Lambda関数のIAMロールにrds-db:connect権限を付与し、接続時にIAMトークンを使用する方法だ。パスワードのローテーションを意識せずに済む点が運用上のメリットだ。
# Pythonの例(IAM認証でRDS Proxyに接続) import boto3 import pymysql rds_client = boto3.client('rds', region_name='ap-northeast-1') # IAMトークンを生成(有効期間: 15分) token = rds_client.generate_db_auth_token( DBHostname='prod-rds-proxy.proxy-xxxx.ap-northeast-1.rds.amazonaws.com', Port=3306, DBUsername='lambda_user' ) connection = pymysql.connect( host='prod-rds-proxy.proxy-xxxx.ap-northeast-1.rds.amazonaws.com', user='lambda_user', password=token, ssl_ca='/path/to/rds-ca-2019-root.pem', ssl={'verify_cert': True} )
3. Lambda実行環境でのコネクション再利用
Lambdaの実行環境はコンテナとして一定時間使い回される(ウォームスタート)。このため、グローバルスコープでDB接続を初期化しておくと、同じ実行環境に次のリクエストが来たときにコネクション確立をスキップできる。RDS Proxyと組み合わせると、ウォームスタート時はProxyの既存コネクションを再利用し、コールドスタート時のみ接続確立が走る。
# グローバルスコープで接続を初期化(Lambdaコンテナの再利用を活かす) import pymysql, os # ハンドラー関数の外に接続を置く connection = None def get_connection(): global connection if connection is None or not connection.open: connection = pymysql.connect( host=os.environ['DB_HOST'], user=os.environ['DB_USER'], password=os.environ['DB_PASSWORD'], database=os.environ['DB_NAME'], connect_timeout=5 ) return connection def lambda_handler(event, context): conn = get_connection() # ... クエリ処理
料金の仕組み(コスト感覚)
RDS Proxyの料金は 「接続先RDBインスタンスのvCPUあたりの時間課金」 だ。RDS本体の料金には含まれないため、追加コストとして計算する必要がある。
| 項目 | 内容 |
|---|---|
| 課金単位 | 接続先インスタンスの vCPU × 時間 |
| 東京リージョン料金(参考) | 約$0.018/vCPU・時(2026年8月時点・公式で確認すること) |
| 無料利用枠 | なし |
| データ転送料 | なし(同一VPC内の通信は無料) |
月額コスト試算例: db.t3.medium(2 vCPU)に対してProxyを1つ立てた場合
$0.018 × 2 vCPU × 24時間 × 30日 = 約$25.9/月(2026年8月時点の参考値。最新料金は公式料金ページを参照)
この費用に対してROIを考えると、コネクション爆発で発生するダウンタイムや、Lambdaからの無駄なコネクション確立コスト(タイムアウトリトライによる課金)を削減できる。また、フェイルオーバー時間短縮により可用性が上がる点も加味すると、月$26前後の追加コストは多くのワークロードで正当化できる。
なお、Aurora Serverless v2 を使っている場合は課金方法が異なり、Proxyのvステップ(ACU)に基づいた課金になる。RDSインスタンスタイプによってコストが変わるため、実環境に合わせて計算してほしい。
応用・実務Tips
Pinningを減らすコーディング指針
・SET文の排除: 可能な限りSESSION変数を使わずクエリパラメータやアプリ側変数で代替する
・プリペアドステートメントはトランザクション内に閉じ込める: BEGIN ~ COMMIT のブロック内で使う
・PostgreSQLの場合、pg_temp テーブルを使わない設計に変更する
監視で使うCloudWatchメトリクス
・ClientConnections: Proxyへの現在の接続数
・DatabaseConnections: ProxyからDB本体への接続数
・DatabaseConnectionsCurrentlySessionPinned: ピン留め中のセッション数(多いと要注意)
・QueryDurationP99: P99クエリレイテンシ(SLO管理に活用)
特に DatabaseConnectionsCurrentlySessionPinned をアラームに設定し、閾値(例: 全セッションの20%)を超えたらSlackに通知するようにしておくと、Pinning問題を早期発見できる。
よくあるトラブルと対処法
「Too many connections」がProxyを入れても直らない
Pinningが多発しているケースが多い。DatabaseConnectionsCurrentlySessionPinned を確認し、数値が高ければアプリのSET文やプリペアドステートメントの使い方を見直す。また、Lambdaの同時実行数の上限設定を超えていないか確認すること(デフォルトでアカウントあたり1,000)。
Lambda から Proxy に接続できない
最初に疑うのはセキュリティグループの設定ミスだ。以下の2点を確認する。
・LambdaのSGからProxyのSGへのアウトバウンド(DBポート: 3306 or 5432)を許可
・ProxyのSGからRDSのSGへのアウトバウンド(同ポート)を許可
次に、LambdaがVPC内のプライベートサブネットに配置されているか確認する。VPC外のLambdaはVPCリソース(Proxy)に直接アクセスできない。
Proxy作成後のレイテンシが上がった
Proxyを経由することでネットワークホップが1つ増えるため、コネクション確立済みの状態では数ミリ秒のオーバーヘッドが生じる場合がある。Pinningが少ない状態でのコネクションプール再利用を正しく実現できれば、全体としては改善するはずだ。それでもレイテンシが問題になる場合は、LambdaとProxy・RDSを同じAZ内に揃える(同一AZサブネット優先)ことでネットワーク遅延を最小化できる。

本記事のまとめ
Lambda × RDS構成でのコネクション問題を解決するためにRDS Proxyが有効な場面と、設計上の注意点を整理した。
| ポイント | 内容 |
|---|---|
| 導入すべきケース | Lambda等の短命プロセスがRDSに大量接続する構成 |
| 主な効果 | コネクション数の削減・フェイルオーバー時間短縮 |
| 最大の落とし穴 | Pinning(多重化が効かなくなる) |
| Pinning回避策 | SET文排除・プリペアドSをトランザクション内に閉じ込める |
| 追加コスト目安 | db.t3.medium相当で約$26/月(2026年8月時点・要確認) |
| 認証強化 | IAM認証でパスワードレス接続が可能 |
| 監視ポイント | DatabaseConnectionsCurrentlySessionPinned を要監視 |
RDS自体の基礎設計についてはAmazon RDS入門を、Aurora との選定比較はAmazon RDS vs Aurora 徹底比較を参照してほしい。サーバーレスアーキテクチャの全体像についてはAWS Lambdaとサーバーレス設計入門もあわせて読んでおくと設計の幅が広がる。
PR
RDS Proxyを含むAWSサービスを活用したクラウドネイティブ設計の全体像を体系的に学べる一冊。アーキテクチャ選定の判断基準とベストプラクティスをまとめた実務向け参考書として使いやすい。
