
New Relic 使ってみた情報をシェアしよう! by New Relic Advent Calendar 2023 シリーズ1、18日目のエントリー記事です。
こんにちはマネージドサービス部 大城です。
New RelicでAmazon DynamoDBのモニタリング統合をやってみました。
DynamoDB作成からNew Relicへの連携、ダッシュボード作成まで一通り書いていきます。画像多めで少し長いのでお急ぎの方は下のまとめを見てください。
DynamoDB作成
まずはDynamoDBを作成します。今回AWSのドキュメント通りに Music テーブルを作成しました。
ステップ 1: テーブルを作成します - Amazon DynamoDB
AWSマネージメントコンソールにログイン、東京リージョンに切替後、AWS CloudShell にて下記を実行します。
スロットリング発生の検証をしたいので ReadCapacityUnits=1,WriteCapacityUnits=1 で作成しています。
aws dynamodb create-table \
--table-name Music \
--attribute-definitions \
AttributeName=Artist,AttributeType=S \
AttributeName=SongTitle,AttributeType=S \
--key-schema \
AttributeName=Artist,KeyType=HASH \
AttributeName=SongTitle,KeyType=RANGE \
--provisioned-throughput \
ReadCapacityUnits=1,WriteCapacityUnits=1 \
--table-class STANDARD
動作確認のためアイテムをputします。
aws dynamodb put-item \
--table-name Music \
--item \
'{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "1"}}'
aws dynamodb put-item \
--table-name Music \
--item \
'{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Howdy"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "2"}}'
アイテムがgetできるか確認します。
aws dynamodb get-item --consistent-read \
--table-name Music \
--key '{ "Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}}'
# -> jsonが返ってきたらOK
AWS Integrationの設定
DynamoDBに限らずAWSのマネージドサービスをNew RelicでモニタリングするにはCloudWatchに出力されるメトリクスをNew Relicに連携する必要があります。
方法としては「API ポーリング」「CloudWatch メトリクスストリーム」の2つがあります。「API ポーリング」は非推奨となっているため「CloudWatch メトリクスストリーム」で設定していきます。
「API ポーリング」「CloudWatch メトリクスストリーム」の特徴については、弊社福田の記事もご参照ください。
連携用のAPI key作成
New RelicにメトリクスをプッシュするためAPI keyを発行します。今回DynamoDB-Integrationという名前で作りました。


CloudWatch メトリクスストリームの設定
New Relic上で Infrastructure > AWS > DynamoDB をクリックします。

Use metric streams をクリックします。

IAMロールを作成するようガイド出るので、AWSマネジメントコンソールよりIAMロールを作成します。



ReadOnlyAccess をアタッチするようガイドが出るのでアタッチします。


IAMロールに名前をつけます。
ガイドでは「NewRelicInfrastructure-Integrations」を推奨していますが、今回「NewRelicInfrastructure-Integrations-test」としました。


AWS Budgetsのポリシー作成の案内が出ますが、今回不要なのでスキップしました。

AWS Integrationの名前を任意でつけます、なんでも良さそうですが今回AWSアカウントIDを設定しました。
作成したIAMロールのARNを入力します。

AWSマネジメントコンソールにサインインしている状態でNew Relic画面上の「Use the CloudFormation Template」をクリックすると、CloudFormationの画面に遷移します。

上で発行したNew RelicのAPI keyを入力しCloudFormationを実行します。

実行が終わると下のリソースが作成されます。

CloudWatch メトリクスストリームの名前空間指定
そのままだとCloudWatch すべての名前空間が転送対象となります。
連携が必要な名前空間だけに絞ります。今回は「AWS/DynamoDB: All metrics names」のみにしました。



ダッシュボード作成
ダッシュボードをテンプレートから作成
用意されているテンプレートを基にダッシュボードを作成してみました。
Dashboards > Create a dashboard をクリックします。

Browse pre-built dashboards をクリックします。

「dynamodb」を検索し出てきたテンプレートをクリックします。

「View dashboard」をクリックします。

ダッシュボード内のNRQL見直し
テンプレートで上手く値が取れないものがあったので、少しNRQLを見直しました。見直ししたNRQLを記載します。

(長いのでクリックしてNRQLを表示してください)
① Request latency, by operation
SELECT average(`aws.dynamodb.SuccessfulRequestLatency.get`) as 'GetItem', average(`aws.dynamodb.SuccessfulRequestLatency.put`) as 'PutItem', average(`aws.dynamodb.SuccessfulRequestLatency.delete`) as 'DeleteItem', average(`aws.dynamodb.SuccessfulRequestLatency.update`) as 'UpdateItem', average(`aws.dynamodb.SuccessfulRequestLatency.query`) as 'Query', average(`aws.dynamodb.SuccessfulRequestLatency.scan`) as 'Scan', average(`aws.dynamodb.SuccessfulRequestLatency.batchGet`) as 'BatchGetItem', average(`aws.dynamodb.SuccessfulRequestLatency.batchWrite`) as 'BatchWriteItem' FROM Metric TIMESERIES
② Throttled requests
SELECT sum(`aws.dynamodb.WriteThrottleEvents`) as 'Write', sum(`aws.dynamodb.ReadThrottleEvents`) as 'Read' FROM Metric
③ System Errors
select sum(`aws.dynamodb.SystemErrors.batchWrite`) as batchWriteError, sum(`aws.dynamodb.SystemErrors.delete`) as deleteError, sum(`aws.dynamodb.SystemErrors.get`) as getError, sum(`aws.dynamodb.SystemErrors.put`) as putError, sum(`aws.dynamodb.SystemErrors.query`) as queryError, sum(`aws.dynamodb.SystemErrors.scan`) as scanError, sum(`aws.dynamodb.SystemErrors.update`) as updateError FROM Metric TIMESERIES
④ User Errors
SELECT sum(`aws.dynamodb.UserErrors.byRegion`) FROM Metric TIMESERIES
⑤ Write throttled requests
SELECT sum(`aws.dynamodb.WriteThrottleEvents`) as 'Write Throttled Requests' FROM Metric TIMESERIES
⑥ Read throttled requests
SELECT sum(`aws.dynamodb.ReadThrottleEvents`) as 'Read Throttled Requests' FROM Metric TIMESERIES
⑦ WriteCapacity %
SELECT 100 * average(`aws.dynamodb.ConsumedWriteCapacityUnits`) / average(`aws.dynamodb.ProvisionedWriteCapacityUnits`) as WriteCapacityPer FROM Metric TIMESERIES
⑧ ReadCapacity %
SELECT 100 * average(`aws.dynamodb.ConsumedReadCapacityUnits`) / average(`aws.dynamodb.ProvisionedReadCapacityUnits`) as ReadCapacityPer FROM Metric TIMESERIES
付録
DynamoDBでSystemErrorやスロットリングを発生させる方法を参考までに記載します。
普段DynamoDBをオペレーションすることがないので、実は一番ここが苦労したところでした。
SystemError
SystemErrorを発生させてNew Relicに連携されるか確認します。実際にDynamoDBをオペレーションしてSystemErrorを発生させるのが、少し面倒だったので直接CloudWatchに書き込みました。
AWS CloudShellよりaws cliを実行してメトリクスの追加を行います。
コマンド
aws cloudwatch put-metric-data \ --namespace 'AWS/DynamoDB' \ --metric-name 'SystemErrors' \ --value "10" \ --unit 'Count' \ --dimensions "TableName=Music","Operation=BatchWriteItem" aws cloudwatch put-metric-data \ --namespace 'AWS/DynamoDB' \ --metric-name 'SystemErrors' \ --value "10" \ --unit 'Count' \ --dimensions "TableName=Music","Operation=DeleteItem" aws cloudwatch put-metric-data \ --namespace 'AWS/DynamoDB' \ --metric-name 'SystemErrors' \ --value "10" \ --unit 'Count' \ --dimensions "TableName=Music","Operation=GetItem" aws cloudwatch put-metric-data \ --namespace 'AWS/DynamoDB' \ --metric-name 'SystemErrors' \ --value "10" \ --unit 'Count' \ --dimensions "TableName=Music","Operation=PutItem" aws cloudwatch put-metric-data \ --namespace 'AWS/DynamoDB' \ --metric-name 'SystemErrors' \ --value "10" \ --unit 'Count' \ --dimensions "TableName=Music","Operation=Query" aws cloudwatch put-metric-data \ --namespace 'AWS/DynamoDB' \ --metric-name 'SystemErrors' \ --value "10" \ --unit 'Count' \ --dimensions "TableName=Music","Operation=Scan" aws cloudwatch put-metric-data \ --namespace 'AWS/DynamoDB' \ --metric-name 'SystemErrors' \ --value "10" \ --unit 'Count' \ --dimensions "TableName=Music","Operation=UpdateItem"
書き込みスロットリング
WriteCapacityUnits=1でテーブルを作成しているため、ある程度書き込みを行えばすぐにスロットリングが発生します。書き込み用のrubyスクリプトを作りました。
put_items.rb
require 'aws-sdk-dynamodb'
require 'securerandom'
REGION = 'ap-northeast-1'
TABLE_NAME = 'Music'
from_count = ARGV[0].to_i
to_count = ARGV[1].to_i
dynamodb_client = Aws::DynamoDB::Client.new(region: REGION)
(from_count.to_i..to_count.to_i).each do |i|
s = SecureRandom.uuid.to_s
table_item = {
table_name: TABLE_NAME,
item: {
Artist: s,
SongTitle: s,
AlbumTitle: s,
Awards: i.to_s
}
}
dynamodb_client.put_item(table_item)
puts "put_item #{table_item.to_s}"
end
1000行のアイテムをテーブルに投入するには下のように実行します。
ruby put_items.rb 1 1000
読み込みスロットリング
こちらもReadCapacityUnits=1 でテーブルを作成しているため、ある程度読み込みを行えばすぐにスロットリングが発生します。読み込み用のrubyスクリプトを作りました。
get_items.rb
require 'aws-sdk-dynamodb'
REGION = 'ap-northeast-1'
TABLE_NAME = 'Music'
dynamodb_client = Aws::DynamoDB::Client.new(region: REGION)
scan_resp = dynamodb_client.scan({table_name: TABLE_NAME})
scan_resp.items.each do |item|
prams = {
key: {
"Artist" => item["Artist"],
"SongTitle" => item["SongTitle"],
},
table_name: TABLE_NAME,
}
get_resp = dynamodb_client.get_item(prams)
puts "get_item #{get_resp.item.to_s}"
end
これを下記のように実行します。
ruby get_items.rb
まとめ
- DynamoDBを新規で作成する
- CloudWatch メトリクスストリームでAWS Integrationを設定する
- テンプレートを基にダッシュボードを作成することができる
- CloudWatchにメトリクスが追加されるとNew Relic側にも反映される
ここまで読んでいただきありがとうございます。この記事が誰かの役に立ったら幸いです。
APMに加えてAWSマネージドサービスもNew Relicに連携することでオブザーバビリティの幅が広がると思います。ぜひ試してみてください。
大城 慶明 (記事一覧)
マネージドサービス部
2022年10月サーバーワークスに入社、沖縄からリモート勤務。AWSを勉強中。沖縄では大城が多いので「よっさん」と呼ばれています。AWS15冠。NRUG沖縄支部運営。X @yo_ohshiro