Skip to content

diamond-writer読解メモ

  • DiamondWriter: 全てをまとめているクラス
  • MetricCache: Redisにストアするための操作が集まっているクラス
  • SeriesTable: DynamoDBを操作するクラス
  • MetricPurger: MetricCache から SeriesTable へ移動するためのクラス

メトリックの粒度と各種エポックタイム

Section titled “メトリックの粒度と各種エポックタイム”

主にRedisで使われるデータポイントの時刻と、主にDynamoDBで使われるアイテムレコードの時刻がある。データポイントの時刻は MetricPointEpoch と表記される。アイテムレコードの時刻は主に ItemEpoch と表記される。

MetricPointEpochItemEpoch は取りうる範囲が決まっている。MetricPointEpoch を1つ進めたときに移動する量を MetricPointEpochStepinterval と呼ぶ。同様に ItemEpoch を進める量は ItemEpochStep となる。

メトリックは粒度ごとに集計される。投稿されたメトリックそのものは1分粒度となる。1分粒度メトリックは、投稿された時刻が秒を含んでいたとしても1分単位に丸め(切り捨て)て記録するので、取得する場合は 21:10:00 のように秒は必ず 00 でなければ取得できない。

また、DiamondWriter は1分粒度を記録すると同時に5分、1時間、1日粒度のメトリックも集計して記録する。このとき addWithAggregation は、平均計算に必要な以前のメトリック値をRedisから取り出す。5分粒度を計算するなら直前の1分粒度を5つ、1時間粒度を計算する場合は直前の5分粒度を12個取り出して平均する。

1分、5分など粒度ごとに値を記録している。キーの名前は以下の形式。

Terminal window
"$(metricPointEpochStep):{$(metricName1)}$(metricName2)"

metricName は一般的に見えるものではなく、OrgIdが頭に付いている。また、Redisクラスターのキー配置を活用するため {} で部分文字列を囲っている。

その時刻に投稿された全てのメトリック名を記録するセット値。cleanup-metric-cache で利用する。

Terminal window
"metricSet:$(metricPointEpochStep):$(itemEpoch)"

末尾が itemEpoch なので1分粒度の場合は4時間分が集められる。過去に複数の粒度が1つのシャードに乗ってしまって処理できなくなったので、1時間、1日粒度の場合は負荷低減するための v2 もある。v1 との違いは分割するかどうか。

Terminal window
"metricSetV2:$(metricPointEpochStep)-$(index):$(itemEpoch)"

DynamoDBに書き込みが終わった時刻を保持する。

Terminal window
"threshold:$(metricPointEpochStep):{$(metricName1)}$(metricName2)"

メトリックを集約するとき、すでにDynamoDBへ書き込まれた値はRedisに残っていない場合があるので、両方の値をマージして集約を行う必要がある。この「DynamoDBに書き込まれているか」を保持するキーが threshold: で始まるもので、DynamoDBに対するリードバッファなので一定期間で消える。

基本的にはRedisの「メトリック値」がそのままコピーされるが、1つのレコードに記録される量が ItemEpochStep 単位となる。そのためレコードの名前も変わる。

DynamoDBそのままのはず。

ストレージと粒度ごとに複数ある。

  • RedisからDynamoDBへ移動する時間 … MetricPointEpochStep
  • DynamoDBからS3へ移動する時間 … ItemEpochStep

前者は diamond-writer がメトリック処理時に行うか、投稿がなくなったメトリックは cleanup-metric-cache が行う。後者は diamond-exporter が行う。

事実上、粒度と各種エポックタイム幅の組み合わせは4通りしかない。

粒度MetricPointEpochStepItemEpochStepTTLDynamoDBのレコード
1分1m4h57h240ポイント
5分5m1d21d288ポイント
1時間1h7d90d168ポイント
1日1d365d730d365ポイント

diamond-writer のクラス設計は以下のようになっている。見れば分かるが、各粒度ごとに SeriesTable, MetricCache, MetricPurger が存在していて、DiamondWriter がそれらを束ねる形となる。

class SeriesTable {
itemEpochStep: ItemEpochStepValue
metricPointEpochStep: MetricPointStepValue
}
class MetricCache {
seriesTable: SeriesTable
interval = seriesTable.metricPointStepValue
}
class DiamondWriter {
metricCaches = {
onemin: new MetricCache(seriesTables.onemin),
fivemin: new MetricCache(seriesTables.fivemin),
...,
}
metricPurgers = {
onemin: new MetricPurger(
metricCaches.onemin,
seriesTables.onemin,
...,
),
...,
}
}

cleanupメソッドは特定の時刻しか処理しない?

Section titled “cleanupメソッドは特定の時刻しか処理しない?”

DiamondWriter#cleanup は与えられたタイムスタンプしか処理していないが、cleanup-metric-cache 側で一定数(デフォルトは10)だけ幅を持たせているので、実行が多少遅れたとしても取り逃がす可能性は低い。diamondのcleanup-metric-cacheが処理する対象も参考に。