メインコンテンツに移動
デベロッパーのためのクラウド活用方法

Amazon DynamoDB に負荷をかけ、検証する方法をご紹介

2023-01-05 | Author : 邵 正

はじめに

皆さんこんにちは、Game Solutions Architect の邵 (@axot) です。

以前 AWS ブログの Amazon DynamoDB スケーリングのベストプラクティス という記事で DynamoDB 運用する際のポイントを紹介しました。

本記事では、DynamoDB に負荷をかける方法をご紹介します。さらに、それを応用してスパイクおよび不均等なアクセスパターンについてのテストおよび解説もご紹介します。最後まで是非ご覧ください !


X ポスト » | Facebook シェア » | はてブ »

builders.flash メールメンバー登録

builders.flash メールメンバー登録で、毎月の最新アップデート情報とともに、AWS を無料でお試しいただけるクレジットコードを受け取ることができます。 
今すぐ登録 »

準備

Amazon DynamoDB 作成

まず、今回のテストのための DynamoDB テーブルを作成します。

ベンチマークではなく、負荷の掛け方や性質を確認が目的なので、ReadCapacityUnits(RCU)、WriteCapacityUnits(WCU) とも最小限に 1 に設定しています。

また、ソートキー については本日のテストで利用しないため、プライマリキーのみを作成しています。

DynamoDB テーブルを作成

コマンド

bash
# 本記事は、aws cli バージョン 2 を利用しています。
# もしバージョン 1 をご利用している場合は、こちらの手順を参考して
# バージョン 2 をインストールしてください
# https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html
$ aws --version
aws-cli/2.9.8 Python/3.9.11 Linux/5.10.147-133.644.amzn2.x86_64 exe/x86_64.amzn.2 prompt/off

$ aws dynamodb create-table \
    --table-name my-load-test \
    --attribute-definitions \
        AttributeName=pk,AttributeType=S \
    --key-schema \
        AttributeName=pk,KeyType=HASH \
    --provisioned-throughput \
        ReadCapacityUnits=1,WriteCapacityUnits=1 \
    --table-class STANDARD

DynamoDB テーブルを作成

ホットスポットやスロットリングされた パーティションキー には、Amazon CloudWatch Contributor Insights for DynamoDB機能が非常に役立ちますので、有効しておきます。テストケース 2 および 3 で利用方法も紹介します。

bash
$ aws dynamodb update-contributor-insights --table-name my-load-test \
    --contributor-insights-action=ENABLE

負荷を掛けるための Amazon EC2 を作成

負荷をかけるために Amazon EC2 を利用します。今回のテストは数 Queries Per Second (1 秒当たりのクエリ件数 / QPS) までを予定していますので、t2.micro レベルで十分です。EC2 自体の作成の方法は割愛します。

bash
$ aws dynamodb update-contributor-insights --table-name my-load-test \ --contributor-insights-action=ENABLE

負荷を掛けるための Amazon EC2 を作成

DynamoDB のテストを行うにあたり、YCSB (Yahoo Cloud Serving Benchmark) というツールを使うことができます。YCSB は、さまざまなシステムを評価するためのツールであり、DynamoDB もサポートしています。YCSB を使うことで、必要な負荷を掛けたり、DynamoDB のスループットやレイテンシーを測定することができます。

bash
# YCSB は JAVA で動作しますので、Amazon が開発した Corretto(OpenJDK) を入れます。
$ sudo yum install -y java-11-amazon-corretto git

# コンパイル済みの YCSB を install
$ curl -O --location https://github.com/brianfrankcooper/YCSB/releases/download/0.17.0/ycsb-0.17.0.tar.gz
$ tar xfvz ycsb-0.17.0.tar.gz

# DynamoDB テストに必要な権限を作成
# 便宜上 IAM User を利用します
$ aws iam create-user --user-name ddb-tester

# 今回対象テーブル my-load-test のフル権限を付与
$ aws iam put-user-policy --user-name ddb-tester --policy-name ddb-test-full --policy-document "$(cat <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "dynamodb:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:dynamodb:*:*:table/my-load-test",
        "arn:aws:dynamodb:*:*:table/my-load-test/index/*"
      ]
    }
  ]
}
EOF
)"

# IAM User のアクセスキーを発行
$ aws iam create-access-key --user-name ddb-tester
{
    "AccessKey": {
        "UserName": "ddb-tester",
        "AccessKeyId": "AKxxxx",
        "Status": "Active",
        "SecretAccessKey": "xxxx",
        "CreateDate": "2022-12-02T05:13:51+00:00"
    }
}

# YCSB が利用する AWS アクセスキーを設定
$ vim AWSCredentials.properties
accessKey =
secretKey =

テスト

ここまでで基本のセットアップが完了しましたので、テストに移ります。

今回のテストでは、3 つのテストを通して負荷の掛け方を示します。テスト 1 では、基本的な負荷を掛ける方法を示します。テスト 2 ではスパイクのトラフィックを再現し、DynamoDB の バーストキャパシティー 機能がどのようにアクセスを処理するかを確認します。テスト 3 は不均等なアクセスパターンを掛けることで、アダプティブキャパシティー がどのように動作するかを解説します。各テストの設定は、dynamodb-common.properties ファイルに共通で記述することもできます。詳細に関しては、YCSB 全体の設定DynamoDB 固有の設定 をご参考ください。

dynamodb-common.properties

記述内容

bash
# YCSB 共通の設定を入れます
$ vim dynamodb-common.properties
dynamodb.awsCredentialsFile = ./AWSCredentials.properties
dynamodb.primaryKey = pk
dynamodb.primaryKeyType = HASH
dynamodb.region = ap-northeast-1
dynamodb.endpoint = http://dynamodb.ap-northeast-1.amazonaws.com.
requestdistribution = uniform
dynamodb.debug = false
dynamodb.connectMax = 100
dynamodb.consistentReads = false
fieldcount = 5
table=my-load-test

# ycsb コマンドを直接利用できるように
$ export PATH=$HOME/ycsb-0.17.0/bin:$PATH

データ投入

負荷かける前に、テストに必要なデータを準備しますので、operationcount で設定されている 100 個のデータを投入します。

bash
# 1 thread で合計 1 QPS の速度でデータを投入
$ ycsb load dynamodb -P test-1 -P dynamodb-common.properties \
  -target 1 -s -threads 1

項目を探索

DynamoDB コンソールの 項目を探索 を利用することで、DynamoDB テーブル内に投入したデータを確認することができます。また、DynamoDB コンソールではデータの追加、編集、削除などの操作も行うことができるため、データの管理をする際にも便利です。

Screenshot of the Amazon DynamoDB web console showing the results of a query on the 'my-load-test' table, displayed in Japanese user interface. The screen displays table fields, returned items, and navigation options.

項目の概要

投入したアイテムのカウントやテーブルのサイズは DynamoDB テーブル の中で確認することもできます。こちらの情報はリアルタイムではないため、少し遅れて表示されます。

Screenshot of the Amazon DynamoDB console showing details for the 'my-load-test' table in Japanese, including table status, partition key information, and item overview.

ライブ項目数を取得

DynamoDB のテーブル内にあるアイテムの数をリアルタイムで取得するには、DynamoDB コンソールのライブ項目数を取得を利用することができます。このボタンをクリックすると、その時点でのテーブル内のアイテム数が表示されます。

ただし、本番環境などでテーブルサイズが大きい場合には、テーブル内のすべてのアイテムをスキャンするために、DynamoDB に大量のリクエストを送信します。このような場合、DynamoDB のスループットを超えるリクエストが発生する可能性がありますので、ご注意ください。

A screenshot of the Amazon DynamoDB user interface in Japanese, displaying a live item count scan with a warning message about scanning large tables and high-traffic tables. The UI includes a completion status and options to rescan or cancel.

負荷をかける

さて、準備はできましたので、いよいよ負荷をかけてみましょう !

bash
# 1 thread で合計 1 QPS の速度 item を update
$ ycsb run dynamodb -P test-1 -P dynamodb-common.properties \
  -target 1 -s -threads 1

結果

今回は更新 (updateproportion) が 100% の負荷を掛けています。DynamoDB のテーブルで更新操作を実行すると、それに伴い Write Capacity Units (WCU) が使用されます。Write Capacity Units (WCU) は、DynamoDB テーブルが 1 秒あたりに書き込める能力を表す概念で、Provisioned Capacity の設定値に基づいて、事前に確保することができます。

DynamoDB コンソール では、Write usage グラフで、Write Capacity Units (WCU) の使用状況を確認することができます。このグラフでは、赤い線が Provisioned Capacity を表し、青い線が実際に観測された Consumed Capacity を表します。また、Write throttled requestsWrite throttled events のカウントも表示されています。今回のテストで、それらが発生していないことも確認できました。これで想定通りの負荷が掛かっていたことは分かります。

Dashboard showing Amazon CloudWatch metrics for a DynamoDB table named 'my-load-test', including read and write usage and throttled requests/events. The graphs display provisioned versus consumed capacity and various request types, aiding in monitoring DynamoDB performance and load testing in an AWS environment.

ケース 2 : スパイクした負荷を掛けてみよう

ケース 2 : スパイクした負荷を掛けてみよう

DynamoDB では短時間のスパイクをベストエフォートで処理できるように、バーストキャパシティー機能を導入しています。

現在、DynamoDB は、未使用の読み込みおよび書き込み容量を最大 5 分 (300 秒) 保持します。読み込みまたは書き込みアクティビティが時折バーストする間、これらの余分な容量ユニットをすばやく消費できます。これは、テーブルに対して定義した 1 秒あたりにプロビジョンされるスループットキャパシティよりも高速です。

また、DynamoDB はバックグラウンドメンテナンスやその他のタスクのために予告なしにバーストキャパシティを消費する場合があります。

これらのバーストキャパシティの詳細は将来変更される可能性があります。 

詳細はこちら » 

これにより、DynamoDB は、スパイクなアクセスを処理するために、通常の読み取りキャパシティーや書き込みキャパシティーを増やすことに加え、バーストキャパシティーを使用しスパイクなアクセスを処理することができるようになります。

シミュレートしてみる

では、スパイクなアクセスをシミュレートして、バーストキャパシティーがどのように動作するかを理解してみましょう。 現在 Write キャパシティーユニットは 1 に設定しているため、バーストキャパシティー最大の容量は 1 WCU x 300s になります。例えばスパイクな Write 負荷を 5 QPS で掛ける場合、 1 WCU x 300s / ( 5 QPS - 1 QPS) = 75s まで耐えられます。

bash
$ cp test-1 test-2

# metrics 観測しやすいように、operationcount を 600 に設定
$ vim test-2 
$ diff -u test-1 test-2
--- test-1    2022-12-02 05:30:06.066016917 +0000
+++ test-2    2022-12-02 06:09:30.256767226 +0000
@@ -1,7 +1,7 @@
 workload=site.ycsb.workloads.CoreWorkload

 recordcount=100
-operationcount=100
+operationcount=600

 readproportion=0
 updateproportion=1

# Write QPS を 5 に変更します。threads 数は増やしても良いですが、
# 5 qps 程度は余裕ですので、そのまま 1 にしてあります。
# threads の計算方法ですが
# 1 + qps/(1000ms/(1 qps の平均 latency))
# が baseline を考えています。
$ ycsb run dynamodb -P test-2 -P dynamodb-common.properties \
  -target 5 -s -threads 1 2>&1 | tee /tmp/test-2.log

# metrics は基本 DynamoDB 側の metrics 見ていますが、
# client latency を知りたい場合は例えば、YCSB の output を解析する方法もあります
# 今回は output の方を解析して、csv に直してグラフにも生成してみました。
$ MODE=UPDATE
$ file=/tmp/test-2.log
$ header=$(echo -n Time,; tail -100 $file | sed -n -e "s/.*$MODE: \([^]]*\).*/\1/p" | sed -e 's/=[^,]*//g' | sed -e 's/ //g' | uniq)
$ content=$(paste -d ',' <(cat $file | egrep '[0-9]{1,4}-[0-9]{1,2}-[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}' | grep $MODE | awk '{print $1,$2}') <(cat $file | sed -n -e "s/.*$MODE: \([^]]*\).*/\1/p" | sed -e 's/[^,]*=//g' | sed -e 's/ //g'))
$ echo "$header"$'\n'"$content" > /tmp/test-2.csv

CloudWatch Contributor Insights for DynamoDB で確認

CloudWatch Contributor Insights for DynamoDB の方では、最もアクセスしたキーや、スロットリングされたキーを確認することができます。今回はバーストキャパシティーを使い切った後スロットリングが発生し、具体的なキー名まで確認できました。この情報を利用することで、パーティションキーの偏りを確認することができます。

Screenshot of AWS CloudWatch Contributor Insights for DynamoDB, displaying visualizations of the most accessed keys and most throttled keys (partition keys) in a table named 'my-load-test'. The image shows time series graphs and user partition keys as part of monitoring and performance analysis.

その他のメトリクス

その他に、全体的に Write usage や、Write throttled requestsWrite throttled events も確認できました。

A dashboard screenshot showing Amazon DynamoDB load test metrics for the 'my-load-test' table, including read and write usage, and counts of throttled requests and events. Key metrics are graphed over time, highlighting spikes in write usage and throttling events.

負荷をかけた側のメトリクス

ここまでのメトリクスでは、DynamoDB 視点でしたが、負荷をかけた側のメトリクスも確認してみましょう。こちらのグラフは test-2.csv から生成されています。負荷は 06:11:18 で開始し、06:12:28 までは Write QPS は 5、レイテンシーは 30ms 以下で安定しています。その後 Write QPS は大きく低下し、レイテンシーも悪化していることがわかります。一方で 75s まではバーストキャパシティーで耐えられる計算通りの動きになります。
A line graph illustrating Write QPS (queries per second) and Write Latency (average ms) for Amazon DynamoDB, annotated in Japanese. The graph displays performance stability up to 75 seconds, with a Japanese note explaining this.

ケース 3 : 不均等なアクセスパターンを掛けてみましょう

ケース 3 : 不均等なアクセスパターンを掛けてみましょう

DynamoDB には、テーブル内のデータを分散するための パーティション という概念があります。パーティションキーをハッシュ化することで、どのパーティションにデータが属するかを決定します。DynamoDB は、パーティション数にかかわらず、項目がテーブルのパーティション全体に渡って均一にディストリビューションされている状態に対して最適化されています。また、DynamoDB にプロビジョンされたキャパシティは、各パーティションに均等に割り当てられます。

では、たとえば不均等なアクセスが発生し、該当パーティションに割り当てられたキャパシティ以上にアクセスがあるとスロットリングされるかどうかの疑問はあるかもしれません。DynamoDB はこのようなアクセスを処理するために、アダプティブキャパシティーという機能を導入しています。公式の例 を確認してみましょう。

アダプティブキャパシティ

次の図は、アダプティブキャパシティの機能を示しています。このテーブルの例のプロビジョニングでは、4 つのパーティション間で 400 WCU が均等に共有されることで、各パーティションで 1 秒間に最大 100 WCU を維持できます。パーティション 1、2、3 はそれぞれ、50 WCU/秒の書き込みトラフィックを受け取ります。パーティション 4 は 150 WCU/秒の書き込みトラフィックを受け取ります。このホットパーティションは、未使用のバーストキャパシティーがある場合でも書き込みトラフィックを受け入ることができます。しかし、バーストキャパシティーだけでは、最終的には 1 秒間に 100 WCU を超えるトラフィックのスロットリングとなります。

DynamoDB アダプティブキャパシティーはパーティション 4 の容量を増大して応答するため、このパーティションはスロットリングされることなく、150 WCU / 秒の高度なワークロードを維持できます。

簡単にまとめますと、プロビジョニング済みキャパシティーが消費されたキャパシティーよりも余っている分は、個別のパーティションで利用は可能となっています。不均等なアクセスがある際もスロットリングなしで耐えられます。注意点としましては、パーティションごとの上限キャパシティーは存在しますので、詳細は 公式ドキュメント を確認してくださいね。

それでは、不均等なアクセスをやってみましょう !

Diagram illustrating an Amazon DynamoDB table with adaptive capacity, showing differences in provisioned and consumed write capacity units (WCUs) across four partitions, and how adaptive capacity increases throughput for high-consumption partitions.

パーティション数を計算

次の図のように、スループットやストレージサイズに応じてそれぞれ独立したパーティション数を計算し、そのうち大きい方を選択する方法になります。注意すべきポイントとして、DynamoDB は実際のパーティション数を運用の過程で自動的に最適な数に増やしますので、利用者は意識する必要はありません。なので、パーティション数に関しては、お客様から直接確認することはできません。

An example diagram in Japanese explaining how to calculate the number of partitions in Amazon DynamoDB based on table size, read capacity units (RCUs), and write capacity units (WCUs). The image includes formulas, a worked example, and explanatory text for partition distribution.

2 つのパーティションを作成

今回のテストでは、アダプティブキャパシティーの性質を示すために、2 つのパーティションを作りますが、通常の利用においては DynamoDB サービスが最適なパーティション数となるよう自動で変更を加えるため、お客様はパーティションを意識する必要はありません。上記の計算式で分かるように、2 つのパーティションを作るには、データを 10GB 以上にするかもしくはスループットを調整すれば実現は可能です。

テスト

今回は Write キャパシティーユニット (WCU) を 1000 に調整し、Read キャパシティーユニット (RCU) を 1 にすることで作ってみました。こちらのテストは一時的にプロビジョン済みの WCU を 1000 にする必要があります。現時点で東京リージョンの場合 1 時間あたりの 1000 WCU のご利用に 0.742 ドルが発生しますので、なる早でプロビジョン済みの WCU を戻しておくようにしましょう。使用料金はリンクからご確認いただけます。

bash
# テスト2からコピーします
$ cp test-2 test-3

# 合計のデータの数 recordcount を 1 にすることで、
# 負荷をかける際には、1 つのキーにのみアクセスすることができます。
# つまり、2 つのパーティションのうち、1 つのパーティションだけにアクセスすることになります。
# また、テスト時間を 10 分以上に調整するために、operationcount を調整ます
$ diff test-2 test-3
3,4c3,4
< recordcount=100
< operationcount=600
---
> recordcount=1
> operationcount=2400

# 二つの partition を作るために、RCU 1、WCU 1000 を一時的にスケール
$ aws dynamodb update-table --table-name my-load-test \
  --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1000

# partition 拡張できるまで待ちます
$ watch aws dynamodb describe-table --table-name my-load-test

# TableStatus が ACTIVE になったら、準備は完了です
$ diff -u /tmp/update_before /tmp/update_after
-    "TableStatus": "UPDATING",
+    "TableStatus": "ACTIVE",
         "CreationDateTime": "2022-12-02T02:26:17.923000+00:00",
         "ProvisionedThroughput": {
-            "LastIncreaseDateTime": "2022-12-02T07:12:57.044000+00:00",
+            "LastIncreaseDateTime": "2022-12-02T07:38:43.756000+00:00",
             "NumberOfDecreasesToday": 0,
             "ReadCapacityUnits": 1,
-            "WriteCapacityUnits": 1
+            "WriteCapacityUnits": 1000
         },
     "TableSizeBytes": 55490,
         "ItemCount": 100,

# Partition 作成した後は、Capacity を小さくしても
# Partition の数は減りません!
# WCU を 2 に設定
$ aws dynamodb update-table --table-name my-load-test \
  --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=2

# これで二つの partition それぞれ 1 WCU がプロビジョンされます
# 今回の負荷は、一つの key だけに 2 write qps をかけてみますが、
# Burst Capacity だけを利用する場合、
# 2 WCU x 300s / ( 2 - 1 ) WCU = 600s
# まで耐えられますが、最終的には Throttling されてしまいます。
# ここで、Adaptive Capacity と併用することで問題なく捌くことができる想定です。
$ ycsb run dynamodb -P test-3 -P dynamodb-common.properties \
  -target 2 -s -threads 1 2>&1 | tee /tmp/test-3.log

CloudWatch Contributor Insights for DynamoDB の結果

CloudWatch Contributor Insights for DynamoDB で一つのキーだけにアクセスされているを確認できました。
Screenshot of the CloudWatch Contributor Insights for DynamoDB dashboard showing the most accessed and most throttled partition keys for the 'my-load-test' table. The chart displays access and throttle data for keys such as 'user6284781860667377211' and 'pk'.

その他のメトリクス

継続した 2 QPS の負荷が 15 分以上にかかり続けていて、プロビジョン済み WCU が 2、消費済み WCU も 2 を確認し、スロットリングが発生していないことも確認できました。想定通りの動きですね。
Screenshot of an Amazon DynamoDB dashboard showing load test metrics for the table 'my-load-test', including read and write usage (average units per second), and counts for throttled requests and events. The dashboard features graphs for provisioned and consumed capacity as well as breakdowns by request type.

クリーンアップ

最後に忘れず、テストで作成したリソースを削除していきます。

bash
# DynamoDB Table の削除
$ aws dynamodb delete-table --table-name my-load-test

# IAM 関連を削除
$ aws iam delete-user-policy --user-name ddb-tester --policy-name ddb-test-full
$ aws iam delete-access-key --user-name ddb-tester --access-key-id xxx
$ aws iam delete-user --user-name ddb-tester

まとめ

今回は DynamoDB に負荷を掛け方を紹介しました。その手法を使用することで、バーストキャパシティーやアダプティブキャパシティーについても解説しました。また、この方法は、大規模なテストや伸縮性能の検証にも使用できるため、ぜひ活用してみてください !

筆者プロフィール

邵 正

Linux カーネル、コンテナ、データベースにフォーカスしています。お客様と協力して様々なクラウドインフラストラクチャのチャレンジを一緒に解決することで、よりヘルシーな設計・運用ができるように、サポートしています。

A portrait of an individual wearing glasses and a dark sweater, set against a dark background.