はじめに
サーバーレスアーキテクチャにおいて、AWS LambdaからAmazon RDS(またはAurora)への接続は、実務で非常によくあるユースケースです。しかし、Lambdaが急激にスケールアウトした際、データベースの最大接続数(コネクション数)の上限に達し、接続エラーが発生することが多々あります。この課題を解決するのが「Amazon RDS Proxy」です。本記事では、LambdaからRDS Proxy経由で安全かつ効率的にデータベースへ接続する設定手順と、実務における設計のベストプラクティスを解説します。
前提知識/必要な理由
- 接続のプーリング:データベース接続をプールして再利用し、RDSのメモリとCPU負荷を軽減します。
- 自動フェイルオーバーの高速化:マルチAZ構成において、フェイルオーバー時の接続切り替え時間を大幅に短縮します。
- セキュリティの向上:IAM認証やAWS Secrets Managerと連携し、データベースの認証情報をセキュアに管理できます。
具体的な設定手順・設計方法
以下は、RDS PostgreSQL/MySQLを対象としたRDS Proxyの設定ステップです。
ステップ1:Secrets Managerでのデータベース認証情報の作成
RDS Proxyはデータベースの認証情報をAWS Secrets Managerから安全に取得します。
- AWSマネジメントコンソールで「Secrets Manager」を開き、「新しいシークレットを保存する」をクリックします。
- 「RDSデータベースの資格情報」を選択し、ユーザー名とパスワードを入力します。
- 対象のデータベースインスタンスを選択し、シークレットに名前を付けて保存します(例:
rds/db-credentials)。
ステップ2:RDS Proxyの作成
次に、データベースとLambdaを中継するプロキシを作成します。
- RDSコンソールの「プロキシ」メニューから「プロキシの作成」をクリックします。
- プロキシ名を設定し、エンジンの種類(MySQLまたはPostgreSQL)を選択します。
- 「接続」セクションで、対象のデータベース(RDSまたはAurora)を選択します。
- 「認証」セクションで、ステップ1で作成したSecrets Managerのシークレットを選択します。
- IAMロールを新規作成するか、既存のロールを選択してプロキシがシークレットにアクセスできるようにします。
ステップ3:Lambda用IAMロールの設定とネットワーク設計
Lambda関数がRDS Proxyに接続するためには、同一のVPC内に配置し、適切なセキュリティグループを設定する必要があります。
- セキュリティグループの設定:RDS Proxyのセキュリティグループにて、Lambdaのセキュリティグループからのインバウンド接続(ポート3306または5432)を許可します。
- LambdaのIAMポリシー:Lambda関数の実行ロールに、RDS Proxyへの接続アクションを許可するポリシーを付与します。
ステップ4:Lambda関数の作成と実装
ここでは、Pythonを使用してRDS Proxy経由でMySQLに接続するLambda関数のコード例を示します。外部ライブラリとして PyMySQL を使用します。
【補足】外部ライブラリ(PyMySQL)の導入手順
Lambda環境には標準で PyMySQL が含まれていないため、以下の手順でローカルでパッケージングしてアップロードするか、Lambdaレイヤーを使用してください。
# ローカルの作業ディレクトリでライブラリをインストール
mkdir python
pip install pymysql -t python/
zip -r pymysql-layer.zip python/
# 作成したzipファイルをLambdaレイヤーに登録し、関数に適用します。
Lambda関数の実装コード
接続先ホスト(DB_HOST)には、データベースのエンドポイントではなく、RDS Proxyのエンドポイントを指定します。
import os
import pymysql
# 環境変数から接続情報を取得
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):
connection = None
try:
# RDS Proxy経由でのデータベース接続
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"Database version: {result[0]}"
}
except Exception as e:
print(f"Error: {e}")
return {
'statusCode': 500,
'body': "Database connection failed"
}
finally:
if connection:
connection.close()
実務での注意点
- ピン留め(Pinning)の回避:トランザクション内で一時テーブルの使用や一部のセッション状態の変更を行うと、RDS Proxyは「ピン留め」と呼ばれる状態になり、特定のLambdaコンテナにコネクションが固定されます。これにより、プーリングの効果が著しく低下するため、不要なセッションの変更は避けてください。
- 追加コストの発生:RDS Proxyは、処理したデータの容量やプロキシが動作するデータベースインスタンスのvCPU数に基づいた課金が発生します。アクセスが少ない小規模なシステムでは、導入費用がメリットを上回る可能性があるため、コスト試算を事前に行いましょう。
- サブネットの選定:RDS Proxyは少なくとも2つのアベイラビリティーゾーン(AZ)のサブネットに関連付ける必要があります。データベース本体と同じサブネット群を選択してください。
まとめ
Amazon RDS Proxyは、サーバーレス構成におけるリレーショナルデータベースへの接続負荷を軽減するための非常に強力なソリューションです。Secrets Managerと強固に連携し、Lambdaの急激なスケーリングにもデータベースを守りつつ安定したシステム構成を実現できます。本記事の手順に沿って、安全かつスケーラブルなインフラを構築してください。