SQS でデータベースへの書き込みの急増を受け止める方法 ── 疎結合で DB を落とさない
記事の「実践」を 1 項目ずつ進めるためのページです。AWS マネジメントコンソールで操作したら、右の一覧にチェックを入れてください。チェックはこのブラウザに保存されます。
前提条件
- リージョン:
ap-northeast-1(東京) - SQS・Lambda・DynamoDB・CloudShell の操作権限を持つ IAM ユーザーまたはロールでコンソールにログイン済みであること
以下のリソースが作成済みであることを前提とします。Lambda 関数 vote-lab-worker は、受け取ったメッセージ 1 件ごとに 0.5 秒かけて DynamoDB に書き込みます(書き込みの遅いデータベースの代わり)。同じ vote_id は 1 回だけ書き込みます。
まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。
| リソース種別 | リソース名 | 内容 | 作り方の参考 |
|---|---|---|---|
| SQS キュー | vote-lab-queue | 標準キュー。可視性タイムアウト 180 秒。デッドレターキュー vote-lab-dlq(最大受信数 5) | Amazon SQS でキューを作り、SNS との違いを体験する |
| SQS キュー | vote-lab-dlq | デッドレターキュー | 同上 |
| Lambda 関数 | vote-lab-worker | Python。タイムアウト 30 秒。SQS の読み取りと DynamoDB への書き込み権限を持つ実行ロール | AWS Lambda で関数を作成しイベント駆動で実行する |
| DynamoDB テーブル | vote-lab-votes | パーティションキー vote_id(文字列)。オンデマンド | Amazon DynamoDB でテーブルを作り Lambda から読み書きする |
手順 1: Lambda に SQS のトリガーを設定し、最大同時実行数を絞る
AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。
上部の検索バーに Lambda と入力し、「Lambda」を選択します。「関数」から vote-lab-worker を開き、「関数の概要」の図にある「トリガーを追加」をクリックします。以下を設定します。
- ソース:
SQS - SQS キュー:
vote-lab-queue(候補から選ぶと、キューの ARN が入ります) - バッチサイズ:
10(デフォルト) - 最大同時実行数:
2(デフォルトは空欄) - トリガーをアクティブ化: オンのまま(デフォルト)
その他の項目はデフォルトのままにして、「追加」をクリックします。
「設定」タブの「トリガー」で、vote-lab-queue のトリガーの状態が Creating から Enabled に変わり、最大同時実行数が 2 であることを確認します。
手順 2: CloudShell から 1,000 件の投票を一気に送る
コンソール上部の CloudShell アイコンから CloudShell を開き、次のコマンドを実行します。10 件ずつまとめて送る send-message-batch を 100 回繰り返し、1,000 件の投票を送ります。
QUEUE_URL=$(aws sqs get-queue-url --queue-name vote-lab-queue --query QueueUrl --output text)
for b in $(seq 1 100); do
ENTRIES=$(for i in $(seq 1 10); do
n=$(( (b - 1) * 10 + i ))
printf '{"Id":"m%d","MessageBody":"{\\"vote_id\\":\\"v%04d\\",\\"choice\\":\\"%s\\"}"}\n' \
"$i" "$n" "$(shuf -n1 -e A B C)"
done | jq -s .)
aws sqs send-message-batch --queue-url "$QUEUE_URL" --entries "$ENTRIES" \
--query 'length(Successful)' --output text
done | awk '{s+=$1} END {print "送信成功:", s, "件"}'
「送信成功: 1000 件」と表示されることを確認します。
手順 3: キューに溜まった投票が一定の速さで減っていくことを確かめる
上部の検索バーに SQS と入力し、「Simple Queue Service」を選択します。
「キュー」の一覧で、vote-lab-queue の「利用可能なメッセージ」と「処理中のメッセージ」の列を確認します。送信直後は利用可能なメッセージが数百〜800 件ほど溜まっており、画面を更新するたびに少しずつ減っていきます。処理中のメッセージは、2 つのワーカーが受け取っている 20 件以下(0・10・20 を行き来します)にとどまります。
ワーカーは 2 つ、1 件あたり 0.5 秒かかるので、書き込みは多くても 1 秒あたり 4 件ほどです。実際には Lambda の起動やキューの受信の時間も加わり、今回は送信を始めてから書き終わるまで 6 分ほどかかりました。
Lambda コンソールに戻り、vote-lab-worker の「モニタリング」タブを開きます。「合計同時実行数」のグラフで、同時実行数が 2 を超えていないことを確認します(凡例に「同時実行数 [最大: 2]」と表示されます)。グラフに反映されるまで数分かかり、時刻は UTC で表示されます。
手順 4: 1 件も欠けずに書き込まれたことを確かめる
SQS コンソールのキューの一覧で、vote-lab-queue の「利用可能なメッセージ」と「処理中のメッセージ」がどちらも 0 になったら、CloudShell で次のコマンドを実行します。
# DynamoDB に書き込まれた投票の件数
aws dynamodb scan --table-name vote-lab-votes --select COUNT --query Count
# デッドレターキューに退避されたメッセージの件数
DLQ_URL=$(aws sqs get-queue-url --queue-name vote-lab-dlq --query QueueUrl --output text)
aws sqs get-queue-attributes --queue-url "$DLQ_URL" \
--attribute-names ApproximateNumberOfMessages --query Attributes.ApproximateNumberOfMessages
投票の件数が 1000、デッドレターキューのメッセージが "0" になっていることを確認します。急増した 1,000 件の投票が、データベースの速さに合わせて 1 件も欠けずに書き込まれました。