スケーラブルなデータ登録基盤を構築する:API Gateway → SQS → Lambda → RDS
こんにちは、エンジニアの後河内です。
今回は、とある案件で直面した「一瞬だけ大量のPOSTデータが飛んでくる」という課題に対してのインフラ構築について紹介します。
常に高負荷ではないものの、特定のタイミングで1000件以上のデータが一気に送信される状況がありました。
このようなスパイクアクセスでは、通常時はリソースを節約する瞬間的な負荷に耐えられる構成が求められます。
要件整理
- ユーザーから送られる大量データを一時的にバッファする
- 遅延やエラーを最小限に抑える
- 最終的に RDS(MySQL)へ確実に保存する
採用したアーキテクチャ
API Gateway → SQS → Lambda → RDS(RDS Proxy経由)
この構成を採用した理由
|
目的 |
手段 |
効果 |
|
大量データの非同期処理 |
SQSを中継 |
スパイク耐性・バッファリング |
|
DB接続の効率化 |
Lambda + RDS Proxy |
同時接続数の制御・安定化 |
|
開発・運用のシンプル化 |
サーバーレス構成 |
自動スケール・低運用コスト |
この構成により、
「スパイクが来てもDBを落とさず、処理は順次安定的に流す」
という仕組みを実現できました。
本記事では、このアーキテクチャの全体像と構築手順を解説します。
図 構成イメージ
構築手順
ステップ1:RDS(MySQL)とRDS Proxyの準備
1.RDSインスタンス作成
- エンジン:MySQL 8.0以上
- パブリックアクセス:オフ
- Lambda から接続可能な VPC / SG(セキュリティグループ)を設定
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2.RDS Proxy作成
- 対象DB:上記のRDS
- デフォルト認証スキーム:なし
- クライアント認証タイプ:MYSQL Native パスワード
- Identity and Access Management (IAM) ロール IAMロールを作成
- Secrets Manager のシークレット 新しいシークレット指定
- IAM 認証 必須
- VPC・SG:Lambdaと同一
→ Lambdaとの接続安定性・効率性が向上
ステップ2:SQSキューの作成
- 名前例:data-sqs-queue
- タイプ:標準キュー
- DLQ(デッドレターキュー)を設定
ステップ3:Lambda関数の実装(Node.js)
- ランタイム:Node.js
- トリガー:SQS (上記で作成したdata-sqs-queue)
- VPC:RDS Proxyと同一
実行ロールの例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes",
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:ap-northeast-1:xxxxxxxxxx:dbuser:prx-xxxxxxxx/*"
}
]
}
Lambdaコード例
import { Signer } from '@aws-sdk/rds-signer';
import mysql2 from 'mysql2/promise';
const RDSConfig = {
hostname: 'xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com',
username: 'xxxxxxx',
region: 'ap-northeast-1',
database: 'xxxxx',
port: 3306
};let config = {};
let lastUpdated = new Date();export const handler = async (event) => {
//DB関連処理
const connection = await createConnection();
try {
await connection.connect();〜処理〜〜
await connection.end();
} catch (e) {
await connection.rollback();
await connection.end();
throw e;
}
};// DB接続
async function createConnection() {
const signer = new Signer({
region: RDSConfig.region,
hostname: RDSConfig.hostname,
port: RDSConfig.port,
username: RDSConfig.username
});
const token = await signer.getAuthToken({ username: RDSConfig.username });
config = {
host: RDSConfig.hostname,
user: RDSConfig.username,
database: RDSConfig.database,
ssl: 'Amazon RDS',
password: token,
authPlugins: { mysql_clear_password: () => () => signer.getAuthToken() }
};
}
return mysql2.createConnection(config);
}
※mysql2は Layer として Lambda に組み込む。組み込み方については下記参考
レイヤーによる Lambda 依存関係の管理
mysql2/promise を使用し、VPC内のLambdaから RDS Proxy 経由で RDSに接続してみた [Node.js]
ステップ4:API Gateway設定(HTTP API)
- パス:POST /submit
- 統合先:SQS(data-sqs-queue)
IAMロールの例
{
"Effect": "Allow",
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:ap-northeast-1:xxxxxxxxxx:data-ingestion-queue"
}
ステップ5:テスト
curl -X POST https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/submit \
-H "Content-Type: application/json" \
-d '{"name": "田中太郎", "email": "tanaka@example.com"}'
確認ポイント
- SQSにメッセージが追加される
- LambdaがCloudWatch Logsに出力を記録
- RDSのusersテーブルにレコードが挿入される
この構成の強みまとめ
|
構成要素 |
メリット |
|
API Gateway → SQS |
即時レスポンス&バッファリング |
|
SQS → Lambda |
非同期処理でスパイクに強い |
|
Lambda → RDS Proxy |
コネクションプールと接続効率化 |
|
Node.js |
軽量・高速なデータ処理 |
まとめ
「一瞬だけ高負荷」というパターンは意外と多く、
常時スケールアップするよりもバッファリング × 非同期処理で解決するのが現実的です。
この構成は、コストを抑えながら高信頼なデータ取り込み基盤を構築したいエンジニアにとって、有力な選択肢になるはずです。
関連記事
お仕事のご相談、採用についてなど、お気軽にお問い合わせください。