Amazon Web Services ブログ
AWS LambdaでAmazon RDS Proxyを使用する
本投稿は、Principal Solutions Architectである George Maoの寄稿によるものです。
更新 – (2020年6月30日 PDT): MySQLおよびPostgreSQL対応のAmazon RDS Proxyが一般にご利用可能になりました。
更新 – (2020年4月8日 PDT): PostgreSQL 互換の Amazon RDS Proxy (プレビュー)を発表しました。プレビューではバージョン10.11と11.5がサポートされています。
AWSサーバーレスプラットフォームは、デマンドに応じて自動的に拡張するアプリケーションを構築することができます。大量アクセスがある間、 Amazon API Gateway と AWS Lambda は負荷に応じて自動的にスケールします。
多くの場合、開発者は、Lambda関数からリレーショナルデータベースに保存されたデータにアクセスする必要が出てきます。しかし、Lambdaからデータベースへの多すぎるコネクションにより過負荷にならないようにすることは難しい場合があります。リレーショナルデータベースの最大同時接続数は、データベースのサイズによって異なります。
これは、各コネクションがデータベースサーバー上のメモリとCPUリソースを消費するためです。Lambda関数は数万の同時接続数までスケールできるため、それに対応するには、データベースはクエリを実行するだけでなく、コネクションを維持するためにより多くのリソースが必要になります。
スケーリングの詳細については、アーキテクチャブログの投稿「サーバーレスアプリを大規模に設計する方法」も参照してください。
Lambdaは数万の同時リクエストに応じて簡単にスケールできるため、そのような状況において、この設計ではバックエンドのリレーショナルデータベースに高い負荷がかかります。通常は、リレーショナルデータベースは、Lambdaのスケーラビリティに応じた同時接続を受け入れるように設計されていません。
Amazon RDSのデータベースプロキシ
本日(2019年12月3日 PST)、Amazon RDS Proxyのプレビューを発表できることを嬉しく思います。
RDS Proxyは、アプリケーションとRDSデータベースの間の仲介役として機能します。RDS Proxyは、必要となるデータベースへのコネクションプールを確立および管理し、アプリケーションからのデータベース接続を少なく抑えます。
データベースへのSQL呼び出しを行うアプリケーションには、RDS Proxyを使用できます。ただし、サーバーレスのコンテキストでは、これによりLambda利用の体験がどのように改善されるかに焦点を当てています。RDS Proxyは、Lambda関数からデータベースに直接流れるすべてのデータベーストラフィックを処理します。
Lambda関数は、データベースインスタンスではなくRDS Proxyと対話します。RDS Proxyは、Lambda関数の同時実行によって作成された大量の同時接続をスケーリングするために必要なコネクションをプーリングします。これにより、Lambdaアプリケーションは、Lambda関数呼び出しごとに新しいコネクションを作成するのではなく、既存のコネクションを再利用できます。
RDS Proxyは自動的にスケーリングされるため、データベースインスタンスでコネクション管理に必要なメモリとCPUリソースが少なくなります。また、暖機されたコネクションプールを使用することでパフォーマンス向上にもつながります。RDS Proxyを使用すると、アイドル接続のクリーンアップとコネクションプールの管理を処理するコードが不要になります。Lambda関数コードは、より簡潔でシンプルとなり、保守性が向上します。
Amazon RDS Proxyを利用してみよう
Amazon RDS Proxyは、プレビューであり、留意事項がいくつかあります。
- 現在、MySQLバージョン5.6または5.7で実行されるAmazon RDS MySQL、または、Aurora MySQLをサポートしています。
- プレビューは、アジア太平洋(東京)、EU(アイルランド)、米国東部(オハイオ)、米国東部(バージニア北部)、米国西部(オレゴン)で利用できます。
- パブリックプレビュー中においては、AWSマネジメントコンソールを使用してRDS Proxyを設定する必要があります。
- プレビューである事に起因した変更が発生する可能性があるため、本番ワークロードにはこのサービスを使用しないでください。
サービスの詳細な説明については、プレビューガイドを確認してください。
前提条件
Amazon RDS MySQL、または、Aurora MySQLのいずれかの既存データベースから始めていきましょう。次に、データベースの認証情報をAWS Secrets Manager にシークレットとして保存し、RDS Proxyがこのシークレットを読み取れるようにするIAMポリシーを作成します。
シークレットを作成するには:
- AWS Secrets Manager にサインインし、Store a new secretを選択します 。
- [Credentials for RDS Database]を選択 します。
- ユーザー名 と パスワードを入力します。
- このシークレットでアクセスするRDSデータベースを選択して、[Next]を選択します。
- シークレット名を入力して、 Nextを選択します。
- すべてのデフォルトを受け入れてStoreを選択します。後で必要になるため、このシークレットに割り当てられたARNをメモしておいてください。
- 次に、RDS Proxyがこのシークレットを読み取ることができるIAMロールを作成します。RDS Proxyは、このシークレットを使用して、データベースへのコネクションプールを維持します。IAMコンソールに移動して、新しいロールを作成します。 前の手順で作成したシークレットにsecretsmanagerアクセス許可を提供するポリシーを追加します 。例えば:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "secretsmanager:GetResourcePolicy", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds" ], "Resource": [ "arn:aws:secretsmanager:us-east-2:[your-account-number]:secret:gmao-rds-secret-YZ2MMN" ] }, { "Sid": "VisualEditor1", "Effect": "Allow",
- 次の信頼ポリシーを追加して、RDSにAssumeRoleを許可しロールを保存します。後で必要になるため、IAMロールのARNをメモします。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "rds.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
プロキシを作成してLambda関数にアタッチします
次に、Lambdaコンソールを使用し て、Lambda関数にデータベースプロキシを追加します。
- AWS Lambdaコンソールにサインインし、RDS Proxyを有効にするLambda関数を開きます。
- Lambda設定ページの一番下までスクロールし、[Add Database Proxy]を選択します。
- データベースプロキシの追加ウィザード に従って、プロキシ識別子 を入力し、RDSデータベースを選択します 。次に、Secrets Managerシークレット と 前に作成した IAMロールを選択します 。RDS Proxyはこのシークレットを使用してデータベースに接続します。[Add] を選択し ます。
- RDS Proxyがプロビジョニングされ、ステータスがAvailableに更新されるまで数分待ちます。
- プロキシを選択して詳細を表示します。Proxyエンドポイントをメモしてください 。これは後でLambda関数コードで必要になります。
これで、Lambda関数に設定済みのRDS Proxyを使用する権限が与えられ、プロキシに接続する準備が整いました。
プロキシを使用する
RDSのDBインスタンスに直接接続する代わりに、RDS Proxyに接続します。これを行うには、2つのセキュリティオプションがあります。IAM認証を使用するか、Secrets Managerに保存されているネイティブのデータベース認証情報を使用できます。IAM認証の方が、実装コードに認証情報を埋め込む必要がないため推奨されます。簡単のために、このガイドでは、Secrets Managerで以前に作成したデータベース資格情報を使用します。
Lambdaがサポートする任意のプログラミング言語を使用できます。以下の例ではNode.jsを使用しています。
let mysql = require('mysql');
let connection;
connection = mysql.createConnection({
host : process.env['endpoint'],
user : process.env['user'],
password : process.env['password'],
database : process.env['db']
});
exports.handler = async (event) => {
console.log("Starting query ...");
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
// Do some work here
connection.end(function(error, results) {
// The connection is terminated now
console.log("Connection ended");
return "success";
});
};
NodeJS MySQLクライアントモジュールをパッケージ化して関数に導入する必要があります。Lambda環境変数を使用して、接続情報を保存します。これはデータベース構成設定のベストプラクティスであるため、コードを更新せずにこれらの詳細を変更できます。 endpoint環境変数は、RDS Proxyエンドポイントを指定しますが、これは前にメモしたものを利用します。 user環境変数と password環境変数は、 データベースの認証情報であり、 db環境変数には、データベース・スキーマ名が格納されています。
IAMで認証することを選択した場合、Lambda実行ロールにrds-db:connectパーミッションが含まれていることを確認してください( ここで概要を説明しています)。Lambdaコンソールは、ユーザーに代わってrds-db:connect 権限を自動的に追加します。このオプションを使用すると、ネイティブのデータベース認証情報を使用する代わりに、IAMから一時トークンを取得してデータベースを認証できます。
まとめ
RDS Proxyは、データベースへの暖機されたコネクションプールを確立することにより、LambdaからRDSデータベースへの多数の接続を管理するのに役立ちます。Lambda関数は必要に応じてスケールでき、RDS Proxy を使用して複数の同時アプリケーションリクエストに対応できます。これにより、データベースのCPUとメモリの要件が緩和され、コード内のコネクション管理ロジックが不要になります。
このプレビュー中にフィードバックをお待ちしております!
翻訳はServerless Specialist Solutions Architect 下川 賢介 (@_kensh)が担当しました。原文はこちらです。