みなさん、サーバレスやってますか?サーバレスコンピューティングは、インフラの保守運用工数を削減するクラウドのメリットに加えて、アプリケーション実行を支えるミドルウェアも抽象化され、開発者はコーディングに集中できるという開発上のメリットがあります。
ステートレスな基盤とは?
リクエストが生じていないアイドルタイムにはCPU、メモリなどのコンピュートリソースは解放されるため課金が生じないか、基盤によっては費用は極小化する、ということからコスト削減も期待できます。ただし同じCPU、メモリを使ったとすると抽象化された分FaaS基盤の方が高くなるケースもあるので、組み合わせで使っていくことが大事です。
この技術特性をステートレスと呼びます。AWS Lambdaを例にとると1リクエスト毎に1マイクロVMが起動します。そして処理が終わった後その環境は解放されます。Google Cloud CloudRunはもう少しサーバに近しい動作をします。ある一定の制限値(デフォルトで80)までは同じ環境でリクエストを処理し、同時リクエスト数が制限値を超えると新しい環境が追加で起動しロードバランサーの下にぶら下がります。
RDBMSとの連携に生じる課題
起動された環境は新規でDBへコネクションを接続します。従来型のサーバで動作するアプリケーションは1環境で複数リクエストを処理します。このため一度接続したDBコネクションを使いまわすことで、新規のコネクション接続におけるデータベースの負荷を下げつつ、処理速度を高速化させています。(コネクションを新規で張るときにレイテンシが発生するためです)
一方 Lambdaの場合、環境自体がステートレスですから、毎回DBとのコネクションも破棄されます。コーディング次第では接続済コネクションをクローズせずにLambdaの実行環境自体が解放されてしまいます。その場合でもDBはもう再利用されないコネクションを一定期間維持することとなるためリソースの無駄が生じます。
FaaS と RDBMS は相性が悪い??
AWS Lambda がリリースされたのは2014年です。その当時はRDBMSへの接続は直接呼び出すしかなく、上記の通りDBリソース上の無駄が生じていました。このことから FaaSとRDBMSの組み合わせは避けるべきという考え方が主流であり、セッションを張る必要のないAmazon DynamoDBとの組み合わせなどが鉄板でした。
しかしながらNoSQLとRDBではやはりそのコンセプトが異なります。どうしてもRDBの方が相性がいいアプリケーションというは存在します。(特に%Like%などあいまい検索を多用するもの)
そこから10年が経過しFaaS基盤からRDBMSへ接続するためのいろいろな手法が今は存在しています。この記事では3回連載でそれらを見ていきたいと思います。
- RDS (SQL) Proxy
- ORM(Object Relational Mapper)
- DataAPIやServerless Driver
第一回目はRDS (SQL) Proxyを見ていきます。
RDS(SQL)Proxyとは?
アプリケーションからデータベースへの接続を効率的に管理します。通常、アプリケーションがデータベースに接続するたびに、新しい接続が確立され、接続数が増えることがあります。これによりデータベースに過剰な負荷がかかることがありますが、RDS Proxyは接続プールを使用して再利用可能な接続を管理し、接続のオーバーヘッドを削減します。
これをAWSマネージドサービスとして提供しているのが AWS RDS Proxyです。
接続のプーリングだけではなく、障害時のフェールオーバーの切り替え、DB接続に用いるクレデンシャルの管理と定期的な自動ローテーションなどの機能が備わっています。
やってみる
Amazon RDS を起動する際に自動でRDS Proxyをセットで起動させることが今は可能となっています。

構築済のRDSに後からアタッチすることも可能ですが、今回は新規RDS構築時にRDS Proxyをまとめて起動します。なお、RDS Proxy はRDS専用のサービスです。EC2上でデータベースを起動している場合は、専用のSQL Proxyを使うことが可能です。MySQLであれば以下のサイトでOSSとして提供されています。
ただRDS Proxyと異なりSQL Proxyの冗長化はEC2側で設計しなければなりません。(当然ですがSQL Proxyが停止すればDB全体が停止したようにアプリケーションからは見えます)
RDS が RDS Proxy 付きで起動すると以下の通り通常のRDSエンドポンとは別にRDS Proxyが付随していることがわかります。

詳細をクリックするとエンドポイントが確認できます。Lambda等のアプリケーションはこちらに対してコネクションを張ることになります。

アイドル時間が長い場合クライアントとのコネクションを解放することも可能です。デフォルトでは30分となっています。ここの設定はクライアントとRDS Proxy間の設定でありRDS Proxy と RDS間ではないことに注意してください。

Proxyの詳細画面からさらにターゲットグループの設定が可能です。

この画面から今度はRDS Proxy と RDS 間の接続設定を行うことが可能です。

この設定はパーセントです。DBのパラメータが保持している最大接続数に対するRDS Proxyが保有するパーセントを設定します。例えばEC2とLambda双方からアクセスを行う場合、以下の様にすることが可能です。
- EC2 --- RDS
- Lambda --- RDS Proxy --- RDS
この場合、後者が利用する接続の最大数をパーセントで設定します。
Lambdaからの接続
Lambdaからの接続はIPが通っていれば普通にエンドポイントを指定するだけですが、RDSの画面からLambda関数のひな形を作成することも可能です。



あとは普通のMySQLと同じように以下のコードで接続が可能です。
// ESMスタイルでmysql2をインポート
import mysql from 'mysql2';
// Lambdaハンドラー
export const handler = async (event) => {
const connection = mysql.createConnection({
host: '<rds proxy endpoint>', // RDSのエンドポイント
user: '<user name>', // MySQLユーザー名
password: '<password>', // MySQLパスワード
database: 'default' // 使用するデータベース名
});
return new Promise((resolve, reject) => {
connection.connect((err) => {
if (err) {
console.error('接続エラー:', err);
reject('接続に失敗しました');
return;
}
console.log('接続成功');
// クエリを実行
connection.query('SELECT * FROM users', (err, results) => {
if (err) {
console.error('クエリエラー:', err);
reject('クエリの実行に失敗しました');
} else {
console.log('クエリ結果:', results);
resolve({
statusCode: 200,
body: JSON.stringify(results),
});
}
// クエリ実行後、接続を終了
connection.end();
});
});
});
});
};