[アップデート] Amazon DynamoDB のオンデマンドキャパシティモードで最大スループットを指定出来るようになったので、YCSB で DynamoDB の負荷テストしてみた

2024.05.03

いわさです。

DynamoDB にはキャパシティモードの概念がありまして、あらかじめ予測したキャパシティを事前割り当てしておくプロビジョンドモードか、実際に発生したリクエストに応じて請求してくれて良いのでうまいことやってくれやというオンデマンドモードの 2 つがあります。

どちらも一長一短あるのですが後者のオンデマンドの場合は柔軟性がある一方で、ワークロードの負荷によってはコストが予測しずらかったり、あるいは DynamoDB のイベントに応じてサービス間を連携しているような場合にオンデマンドだと外部サービスに予測できない負荷が発生することがありえます。

そんなオンデマンドキャパシティモードですが、本日のアップデートで最大テーブルスループットが設定出来るようになりました。
まだ AWS What's New でアナウンスされていませんが、DynamoDB 公式ドキュメントの変更履歴としてはアナウンス済みです。

本日はこちらを設定して DynamoDB に負荷をかけてみましたのでその様子を紹介します。

2024.05.04 追記

アナウンスもされておりました。

「読み込み/書き込みキャパシティーの設定」のオプションとして設定可能

この最大スループット設定はテーブル単位で行います。
設定方法は簡単で、新規テーブル作成時であればオンデマンドキャパシティ選択時に以下からオプションが選択可能です。

DynamoDB ではオンデマンドキャパシティモードとプロビジョンドキャパシティモードで料金計算に使われる単位が異なってます。

  • オンデマンドキャパシティモード
    • 読み取りリクエスト単位(RRU)
    • 書き込みリクエスト単位(WRU)
  • プロビジョンドキャパシティモード
    • 読み取りキャパシティ単位(RCU)
    • 書き込みキャパシティ単位(WCU)

で、今回のオプションで指定するのは最大の RRU/秒 と WRU/秒 を設定することが出来ます。
どちらかだけの設定も可能です。
設定可能な範囲は最小が 1 で、最大が 40,000 です。

なお、この最大スループットはベストエフォートベースでの適用であるとドキュメントに記載されており、超過しないことが保証されたものではありません、有効ではありますが目安であると認識しておきましょう。

設定されていると次のように概要タブから確認が可能です。

既存テーブルへの有効化

新規テーブルではなく既存テーブルへの設定も可能です。
キャパシティーの編集から設定が可能です。

既存テーブルの場合だと、RRU と WRU の実績を参照しながら、最大スループットを設定することも出来ます。
これは中々便利です。下回った数値を設定しようとすると「良いんだな?」と聞かれます。

なお、DynamoDB のキャパシティモード変更は 24 時間に 1 回までという制限がありましたが、最大スループットモードの ON/OFF やしきい値の変更は何度でも出来るようでした。

GSI (グローバルセカンダリインデックス) も設定可能

グローバルセカンダリインデックスの作成時も同オプションを設定可能です。
ベーステーブルからコピーも出来ますし、個別の設定で上書きも可能です。

メトリクスが追加されてる

なお、最大スループットの設定値は CloudWatch メトリクスとして確認することも出来ます。
OnDemandMaxReadRequestUnitsOnDemandMaxWriteRequestUnitsが追加されています。
これらのメトリクスは今回の機能で設定された最大スループットであり、実際に消費された WRU や RRU ではないので注意しましょう。

負荷テストしてみた

さて今回最大スループットが設定出来るようになったので実際に使って挙動を観察してみたいと思います。
次のようにオンデマンドモードで最大 RRU、WRU に 1 を設定したテーブルに対して負荷をかけてみます。

DynamoDB テーブルへの負荷は次の記事を参考に YCSB を使ってみます!
手順は概ね以下の記事のとおりですので本ブログでは割愛させて頂きます。

最初のデータ作成 100 件は次のような結果となりました。
targetオプションはops/secでして、ワークロードファイル「test-1」で 100 件を指定しているので、100 秒かけて実行される感じです。

$ ./ycsb load dynamodb -P test-1 -P dynamodb-common.properties -target 1 -s -threads 1

:

[OVERALL], RunTime(ms), 102300
[OVERALL], Throughput(ops/sec), 0.9775171065493646
[TOTAL_GCS_Copy], Count, 11
[TOTAL_GC_TIME_Copy], Time(ms), 38
[TOTAL_GC_TIME_%_Copy], Time(%), 0.03714565004887586
[TOTAL_GCS_MarkSweepCompact], Count, 1
[TOTAL_GC_TIME_MarkSweepCompact], Time(ms), 19
[TOTAL_GC_TIME_%_MarkSweepCompact], Time(%), 0.01857282502443793
[TOTAL_GCs], Count, 12
[TOTAL_GC_TIME], Time(ms), 57
[TOTAL_GC_TIME_%], Time(%), 0.05571847507331378
[CLEANUP], Operations, 1
[CLEANUP], AverageLatency(us), 2.0
[CLEANUP], MinLatency(us), 2
[CLEANUP], MaxLatency(us), 2
[CLEANUP], 95thPercentileLatency(us), 2
[CLEANUP], 99thPercentileLatency(us), 2
[INSERT], Operations, 100
[INSERT], AverageLatency(us), 24826.6
[INSERT], MinLatency(us), 7844
[INSERT], MaxLatency(us), 387583
[INSERT], 95thPercentileLatency(us), 37823
[INSERT], 99thPercentileLatency(us), 41759
[INSERT], Return=OK, 100

まぁここは、クライアント側で 1 秒間に 1 回 PUT する感じなので、最大スループットはあまりに関係ないですね。

最大スループットに到達するとスロットリングが発生する

続いてスパイクを想定した負荷をかけてみます。
ワークロードファイルのオペレーションを 600 に増やして、秒間 6 件処理させてみました。どうなるかな。

$ ./ycsb run dynamodb -P test-1 -P dynamodb-common.properties -target 6 -s -threads 1                                                           

:

258250 [Thread-2] ERROR site.ycsb.db.DynamoDBClient  -com.amazonaws.AmazonServiceException: Throughput exceeds the maximum OnDemandThroughput configured on table or index (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ThrottlingException; Request ID: MGKC1TCAIL6D7J8CIRMO8O621VVV4KQNSO5AEMVJF66Q9ASUAAJG)
2024-05-02 22:30:25:997 260 sec: 590 operations; 0.5 current ops/sec; est completion in 5 second [UPDATE-FAILED: Count=3, Max=4132863, Min=3809280, Avg=4005546.67, 90=4132863, 99=4132863, 99.9=4132863, 99.99=4132863] [UPDATE: Count=2, Max=627711, Min=585216, Avg=606464, 90=627711, 99=627711, 99.9=627711, 99.99=627711] 

:

スロットリングが発生していますね。
設定した最大スループットに到達してサーバー側からリクエスト調整されています。
クライアント側はここで終了しても良いですし、時間をおいてリトライしても良い感じです。

メトリクス上も「調整されたリクエスト」つまりスロットリングのことなのですが、どの程度発生しているのか確認出来ます。

バーストキャパシティ機能の影響を受ける

ただ、テスト結果を見てみると実行時間やスループットを見てみると期待していたより処理されています。

:

[CLEANUP: Count=1, Max=2, Min=2, Avg=2, 90=2, 99=2, 99.9=2, 99.99=2] [UPDATE: Count=10, Max=563711, Min=5200, Avg=62632.8, 90=13559, 99=563711, 99.9=563711, 99.99=563711] 
[OVERALL], RunTime(ms), 260187
[OVERALL], Throughput(ops/sec), 2.306033737273576
[TOTAL_GCS_Copy], Count, 19
[TOTAL_GC_TIME_Copy], Time(ms), 49
[TOTAL_GC_TIME_%_Copy], Time(%), 0.018832608854400874
[TOTAL_GCS_MarkSweepCompact], Count, 1
[TOTAL_GC_TIME_MarkSweepCompact], Time(ms), 15
[TOTAL_GC_TIME_%_MarkSweepCompact], Time(%), 0.005765084343183941
[TOTAL_GCs], Count, 20
[TOTAL_GC_TIME], Time(ms), 64
[TOTAL_GC_TIME_%], Time(%), 0.024597693197584813
[UPDATE-FAILED], Operations, 30
[UPDATE-FAILED], AverageLatency(us), 3951820.8
[UPDATE-FAILED], MinLatency(us), 3608576
[UPDATE-FAILED], MaxLatency(us), 4231167
[UPDATE-FAILED], 95thPercentileLatency(us), 4214783
[UPDATE-FAILED], 99thPercentileLatency(us), 4231167
[CLEANUP], Operations, 1
[CLEANUP], AverageLatency(us), 2.0
[CLEANUP], MinLatency(us), 2
[CLEANUP], MaxLatency(us), 2
[CLEANUP], 95thPercentileLatency(us), 2
[CLEANUP], 99thPercentileLatency(us), 2
[UPDATE], Operations, 570
[UPDATE], AverageLatency(us), 146898.98596491228
[UPDATE], MinLatency(us), 4956
[UPDATE], MaxLatency(us), 4202495
[UPDATE], 95thPercentileLatency(us), 619519
[UPDATE], 99thPercentileLatency(us), 3725311
[UPDATE], Return=OK, 570
[UPDATE], Return=ERROR, 30

DynamoDB にはバーストキャパシティの概念がありまして、公式ドキュメントによるとオンデマンドモードの場合でもバーストキャパシティが原因で指定された最大スループットを超える可能性があるとのことです。

テスト実行時間は約 4 分間でしたが、序盤はバーストが使われているためか結構なスループットが出ています。
約 5 WCU/秒 ですね。

中盤からはバースト分が消費されたためか、約 1 WCU/秒で推移しています。

バーストキャパシティ機能の影響を受けていることがわかりますね。

最大スループットはベストエフォート

その後何度か負荷をかけてみました。次は 1 分単位合計のConsumedWriteCapacityUnitsメトリクスです。
以下の 3 つ目の負荷はバーストキャパシティを使い切ったであろうというタイミングで開始したスパイクです。

約 1 WCU/秒ですが、少しばらつきがありますね。
クライアント環境にも左右されそうですが、ベストエフォートと言及されていた点かもしれません。
でも概ね期待どおり動作してそうですね。良い感じです。

さいごに

本日は Amazon DynamoDB のオンデマンドキャパシティモードで最大スループットを指定出来るようになったので実験してみました。

キャパシティプランニングをしたくない、従量課金ベースで柔軟に動いてほしいと思いつつ、「無制限に料金が発生するのもちょっと困るわ」という場合に良い選択肢になるのではないでしょうか。