はじめに
サーバーレスアーキテクチャの普及に伴い、AWS LambdaからAmazon RDS(またはAurora)へのアクセスは一般的な構成となっています。しかし、Lambdaのスケールアウト特性により、データベース(DB)への同時接続数が急増し、接続制限(Connection Limit)を超えてシステム全体がダウンするトラブルが頻発しています。
本記事では、この課題を解決する「Amazon RDS Proxy」を導入し、Lambdaから安全かつ効率的にデータベースへ接続するための設定手順と設計のベストプラクティスを分かりやすく解説します。
前提知識/必要な理由
Lambdaはリクエスト数に応じて自動で並行実行数を増やします。しかし、従来のRDBMS(MySQLやPostgreSQLなど)は、確立されたコネクションを維持する設計になっており、短時間に大量の接続・切断を繰り返す仕組み(ステートレスな通信)には適していません。
RDS Proxyを仲介させることで、以下のメリットが得られます。
- コネクションプーリング:確立されたDB接続を使い回し、新規接続のオーバーヘッドを削減します。
- 接続数の制限:DBの最大接続数を超えるリクエストをProxy側でキューイングし、DBの枯渇を防ぎます。
- 可用性の向上:Auroraのフェイルオーバー時の切り替え時間を最大66%短縮します。
具体的な設定手順・設計方法
ここでは、VPC環境内に構築された「Amazon RDS for MySQL」に対し、「Amazon RDS Proxy」を構築し、「AWS Lambda (Python 3.11)」から安全に接続する手順を解説します。
ステップ1:Secrets Managerでの認証情報の作成
RDS Proxyを利用するには、データベースの認証情報をAWS Secrets Managerに登録する必要があります。
- Secrets Managerのコンソールを開き、「新しいシークレットを保存する」をクリックします。
- シークレットのタイプで「RDSデータベースの資格情報」を選択し、ユーザー名とパスワードを入力します。
- 対象のRDSデータベースを選択し、シークレットを保存します(例:
my-db-secret)。
ステップ2:IAMロールとポリシーの設定
RDS ProxyがSecrets Managerから認証情報を取得できるようにするためのIAMロールを作成します。以下のポリシーを付与したロールを作成してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDecryptSecret",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:my-db-secret-*"
},
{
"Sid": "AllowKMSDecrypt",
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.ap-northeast-1:amazonaws.com"
}
}
}
]
}
ステップ3:RDS Proxyの作成
- RDSのコンソールから「プロキシ」を選択し、「プロキシの作成」をクリックします。
- プロキシ識別子を入力し、エンジンに「MySQL」を選択します。
- 「対象データベース」で接続先のRDSインスタンスを選択します。
- 「認証」セクションで、ステップ1で作成したシークレットと、ステップ2で作成したIAMロールを選択します。
- VPC、サブネット、セキュリティグループを設定してプロキシを作成します。
ステップ4:Lambda関数の作成とライブラリの導入
Lambda関数からRDS Proxy経由で接続するためのPythonコードを作成します。今回はDB接続ライブラリとして PyMySQL を使用します。
【重要】外部パッケージ(PyMySQL)の導入手順
Lambdaの標準環境には PyMySQL が含まれていないため、以下の手順でLambdaレイヤーとしてアップロードするか、デプロイパッケージに含める必要があります。
# ローカルでの準備手順(Linux/Mac推奨)
mkdir -p python/lib/python3.11/site-packages
pip install pymysql -t python/lib/python3.11/site-packages/
zip -r pymysql-layer.zip python/
作成した pymysql-layer.zip をAWS Lambdaのコンソールから「レイヤー」として登録し、対象のLambda関数に紐づけてください。
Lambda関数のコード例
import os
import pymysql
# 環境変数からRDS Proxyのエンドポイント等を取得
DB_HOST = os.environ['DB_HOST'] # RDS Proxyのエンドポイント
DB_USER = os.environ['DB_USER']
DB_PASSWORD = os.environ['DB_PASSWORD']
DB_NAME = os.environ['DB_NAME']
def lambda_handler(event, context):
try:
connection = pymysql.connect(
host=DB_HOST,
user=DB_USER,
password=DB_PASSWORD,
database=DB_NAME,
connect_timeout=5
)
with connection.cursor() as cursor:
cursor.execute("SELECT version();")
result = cursor.fetchone()
return {
'statusCode': 200,
'body': f"Connected successfully. DB Version: {result[0]}"
}
except Exception as e:
print(f"Error: {e}")
return {
'statusCode': 500,
'body': "Connection failed"
}
finally:
if 'connection' in locals() and connection.open:
connection.close()
実務での注意点
- ピン留め(Pinning)の回避:SQLの特定機能(セッション変数の変更、一時テーブルの使用、プリペアドステートメント等)を使用すると、RDS Proxyが特定の接続を固定(ピン留め)してしまい、コネクション共有の効果が得られなくなるため注意が必要です。
- セキュリティグループの設計:LambdaからRDS Proxyへのアウトバウンド通信、およびRDS ProxyからRDS本体へのインバウンド通信が、セキュリティグループで適切に許可されていることを必ず確認してください。
- 追加コスト:RDS Proxyは起動している時間と処理されたデータ量(1GBあたり)に対して課金されます。トラフィックの少ない開発環境などでは、コストパフォーマンスを考慮した上で導入を検討してください。
まとめ
AWS Lambdaからリレーショナルデータベースに接続する際、RDS Proxyの導入は接続枯渇トラブルを防ぐための必須のベストプラクティスです。Secrets Managerによるセキュアな認証情報の管理と適切なネットワーク設計を行うことで、高負荷な実務環境でも耐えうる堅牢なサーバーレスシステムを構築できます。ぜひ本手順を参考に導入してみてください。