DynamoDB運用者必見!!頻繁にアクセスされるキーが見やすくなりました!

2020.04.03

こんにちは(U・ω・U) AWS事業部の深澤です。

全国のDynamoDBファンの皆さん、CloudWatch Contributor InsightsのGAに伴い、CloudWatch Contributor Insights for Amazon DynamoDBが公開されましたよ!!

今回はこの機能についてお届けしようと思います!

どんな機能なの?

アクセスが多いキーを検出するための機能です。DynamoDBではパーティションキーによって書き込むディスク(パーティション)を分けて負荷を分散しているのですが同じパーティションキーに対して書き込みが多くなってしまうと同じディスクにアクセスが集中し性能が偏ってしまうという性質があります。なのでキーの偏りを検出するというのはDynamoDBのチューニング上非常に重要です。特にプロビジョニング済みキャパシティモードを採用されている方は更新されるキーに偏りがあった場合、アダプティブキャパシティーが発生し、キーによっては性能低下をもたらす恐れがあるので要注意です。

何が新しいの?

これまではDynamoDBではConsumedReadCapacityUnitsやConsumedWriteCapacityUnitsといったメトリクスで消費したユニット数を監視する事ができたり、それぞれのThrottleEventsを監視する事でプロビジョニング以上のアクセス負荷発生の検知はできましたがいずれもテーブルやインデックス単位まででした。実際にテーブルに保存されたキー単位で負荷を検知できるというのが今回の新しい機能です。

実際にやってみた

今回はこちらの公式ドキュメントで提供されている「ProductCatalog のサンプルデータ」を用いてテーブルを作成、検証していきます!

作成とデータの挿入コマンドは以下通りです。

aws dynamodb create-table \
--table-name ProductCatalog \
--attribute-definitions AttributeName=Id,AttributeType=N \
--key-schema AttributeName=Id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"101"},"Title":{"S":"Book101Title"},"ISBN":{"S":"111-1111111111"},"Authors":{"SS":["Author1"]},"Price":{"N":"2"},"Dimensions":{"S":"8.5x11.0x0.5"},"PageCount":{"N":"500"},"InPublication":{"B":"true"},"ProductCategory":{"S":"Book"}}'

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"102"},"Title":{"S":"Book102Title"},"ISBN":{"S":"222-2222222222"},"Authors":{"SS":["Author1","Author2"]},"Price":{"N":"20"},"Dimensions":{"S":"8.5x11.0x0.8"},"PageCount":{"N":"600"},"InPublication":{"B":"true"},"ProductCategory":{"S":"Book"}}'

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"103"},"Title":{"S":"Book103Title"},"ISBN":{"S":"333-3333333333"},"Authors":{"SS":["Author1","Author2"]},"Price":{"N":"2000"},"Dimensions":{"S":"8.5x11.0x1.5"},"PageCount":{"N":"600"},"InPublication":{"B":"false"},"ProductCategory":{"S":"Book"}}'

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"201"},"Title":{"S":"18-Bike-201"},"Description":{"S":"201Description"},"BicycleType":{"S":"Road"},"Brand":{"S":"MountainA"},"Price":{"N":"100"},"Gender":{"S":"M"},"Color":{"SS":["Red","Black"]},"ProductCategory":{"S":"Bicycle"}}'

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"202"},"Title":{"S":"21-Bike-202"},"Description":{"S":"202Description"},"BicycleType":{"S":"Road"},"Brand":{"S":"Brand-CompanyA"},"Price":{"N":"200"},"Gender":{"S":"M"},"Color":{"SS":["Green","Black"]},"ProductCategory":{"S":"Bicycle"}}'

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"203"},"Title":{"S":"19-Bike-203"},"Description":{"S":"203Description"},"BicycleType":{"S":"Road"},"Brand":{"S":"Brand-CompanyB"},"Price":{"N":"300"},"Gender":{"S":"W"},"Color":{"SS":["Red","Green","Black"]},"ProductCategory":{"S":"Bicycle"}}'

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"204"},"Title":{"S":"18-Bike-204"},"Description":{"S":"204Description"},"BicycleType":{"S":"Mountain"},"Brand":{"S":"Brand-CompanyB"},"Price":{"N":"400"},"Gender":{"S":"W"},"Color":{"SS":["Red"]},"ProductCategory":{"S":"Bicycle"}}'

aws dynamodb put-item \
--table-name ProductCatalog \
--item '{"Id":{"N":"205"},"Title":{"S":"20-Bike-205"},"Description":{"S":"205Description"},"BicycleType":{"S":"Hybrid"},"Brand":{"S":"Brand-CompanyC"},"Price":{"N":"500"},"Gender":{"S":"B"},"Color":{"SS":["Red","Black"]},"ProductCategory":{"S":"Bicycle"}}'

無事にテーブルが作成できました!

さて最初テーブルを作成した段階だとContributor Insightsは無効になっていますのでこちらをオンにします。マネジメントコンソールで行う場合には「投稿者のインサイト」タブをクリックし、「投稿者のインサイトを管理」ボタンをクリックします。

すると次のようなポップアップが出てきますので、「投稿者のインサイトのステータス」を有効にして「確認ボタン」を押します。

すると次のような画面になり、Contributor Insightsが有効になります。

なおこちらの手順ですが、CLIでも実施可能です。CLIの場合は以下のコマンドを実行するだけです。

aws dynamodb update-contributor-insights --table-name ProductCatalog --contributor-insights-action=ENABLE

{
"TableName": "ProductCatalog",
"ContributorInsightsStatus": "ENABLING"
}

さて有効になったところで実際に特定のキーに対してアクセスしてみようと思います!!今回は次のようなpythonコードを用意してみました。

import boto3
import random

client = boto3.client('dynamodb')
i = 0

while i < 15:
res = client.get_item(
TableName='ProductCatalog',
Key={'Id': {'N': str(random.randint(101, 103))}}
)
i += 1

さてこれらのアクセスをContributor Insightsで検知できるのでしょうか。結果は次のようになりました。 しっかり反映されてますね!どのくらいのキャパシティユニットが消費されたのかよく分かります。これでも十分なのですが、CloudWatch側ではアクセスの多いキー順に順位を絞って表示したりアクセスの逼迫しているキーをわかりやすく並べてくれたり表示する時間を絞ったりとより分析がしやすくなっています。

さらにこちらインデックスにも適用可能とのこと。早速試してみましょう。以下のコマンドでテーブルにグローバルセカンダリインデックスを付与してみます。

aws dynamodb update-table \
--table-name ProductCatalog \
--attribute-definitions \
AttributeName=ProductCategory,AttributeType=S \
AttributeName=Title,AttributeType=S \
AttributeName=BicycleType,AttributeType=S \
AttributeName=Price,AttributeType=N \
--global-secondary-index-updates '[{
"Create": {
"IndexName": "BicycleType-Price-index",
"KeySchema": [
{ "AttributeName": "BicycleType", "KeyType": "HASH" },
{ "AttributeName": "Price", "KeyType": "RANGE" }
],
"Projection": { "ProjectionType": "ALL" }
}
}]'

すると追加したグローバルセカンダリインデックスが先ほどのContributor Insights管理画面に出てきました。 無効になっているので先ほどの手順と同様にこちらも有効にしてみます。 なお、こちらはCLIでも有効にすることが可能です。

aws dynamodb update-contributor-insights --table-name ProductCatalog --index-name BicycleType-Price-index --contributor-insights-action=ENABLE

それでは設定したグローバルセカンダリインデックスに対してクエリを投げてみます!

import boto3

client = boto3.client('dynamodb')

res = client.query(
TableName='ProductCatalog',
IndexName='BicycleType-Price-index',
ExpressionAttributeValues={
':type': {
'S': 'Road',
}
},
KeyConditionExpression='BicycleType = :type'
)

しばらくするとグローバルセカンダリインデックスのパーティションキーに対して読み込みがあったことがContributor Insightsに反映されました!

料金について

こちらはCloudWatch側の課金となります。有効となったContributor Insightsのルール数と、そのルール毎に処理されたDynamoDBイベント数によって計算されます。

CloudWatch Contributor Insights for Amazon DynamoDBは有効にするとキーの数によって次のようにルールが作成されます。

  • パーティションキー
  • ルール数:2
  • 最もアクセスが多い項目 (パーティションキー)
  • 最もスロットリングされた項目 (パーティションキー)
  • 複合パーティションキー
  • ルール数:4
  • 最もアクセスが多い項目 (パーティションキーのみ)
  • 最もアクセスが多い項目 (パーティションキーとソートキー)
  • 最もスロットリングされた項目 (パーティションキーのみ)
  • 最もスロットリングされた項目 (パーティションキーとソートキー)

これはテーブルだけではなく、グローバルセカンダリインデックスについても同様です。例えば複合パーティションキーのテーブルに複合パーティションキーのグローバルセカンダリインデックスを付与したとすると合計8つのルールが作成されることになります。ルール毎に0.50USD/月の料金が発生します。

そしてそれぞれのルール毎に発生したイベント数分課金が発生します。このイベントとはDynamoDBデータプレーンのオペレーションのことを指します。

例えば、パーティションキーのみのテーブルに対してGetItemを行った場合に発生するイベント数は1ですが、複合パーティションキーの場合にはパーティションキーとソートキーでイベント数は2となります。このイベントで発生する料金ですが、ルール/月に一致する100万件のイベントごとに0.034USDとなっています。

最後に

いかがでしたでしょうか!コストはややかかりますが、DynamoDBでスロットリングが発生した際の原因切り分けがスムーズに行えることを考慮すると決して高いサービスではないと思います。既存のテーブルにも導入可能という観点からプロビジョニング済みキャパシティモードを採用されている方は是非導入を検討されてみてはいかがでしょうか。またオンデマンドキャパシティモードであったとしてもこちらのContributor Insights for Amazon DynamoDBを使うことでDynamoDBのチューニングが行いやすくなり、よりプロビジョニング済みキャパシティモードへの切り替え検討がしやすくなるのではと思います。

以上、深澤(@shun_quartet)でした!