CloudWatch カスタムメトリクス送信で Period 境界のデータ欠落を防ぐ
問題
systemd timer で60秒間隔に CloudWatch カスタムメトリクスを PutMetricData で送信していたところ、CloudWatch コンソールのグラフが断続的に欠落(歯抜け)する現象が発生した。
原因
systemd timer の OnUnitActiveSec=60 は「前回の実行完了から60秒後」に次を起動する。スクリプトの実行時間(数秒)が毎回加算されるため、送信タイミングが徐々にドリフトする。
CloudWatch の Period=1分(00秒〜59秒)の境界をまたぐタイミングで、その1分間にデータポイントが0個になりグラフが途切れる。
Period: |--- 16:44 ---|--- 16:45 ---|--- 16:46 ---|
送信: 16:44:02 16:45:05 16:46:08
↑ ドリフトで 16:45 の Period に入らない場合がある
対策
送信間隔を Period より短くして、どの1分間にも必ず1回以上データポイントが入るようにする。
[Timer]
OnBootSec=50
OnUnitActiveSec=50
AccuracySec=1
OnUnitActiveSec=50— 50秒間隔にすることでドリフトしても1分の Period を超えないAccuracySec=1— デフォルトの1分から短縮し、タイマーのジッターを抑える
他の選択肢
| 方法 | メリット | デメリット |
|---|---|---|
| 送信間隔を短くする(50秒) | シンプル、変更が小さい | API コール数が約20%増(無料枠内なら問題なし) |
| Period を5分にする | 確実にデータが入る | グラフの粒度が粗くなる |
| CloudWatch Agent の StatsD 連携 | Agent がバッファリング・送信を管理 | Agent の導入・設定が別途必要 |
補足: CloudWatch Agent の StatsD 連携とは
CloudWatch Agent には StatsD プロトコル(UDP)のリスナーが組み込まれている。スクリプトが UDP でローカルの Agent にメトリクスを投げ、Agent が一定間隔でまとめて CloudWatch に送信する構成。Agent 側が送信タイミングを管理するためドリフト問題が起きにくい。ただし Agent の導入が前提となる。
まとめ
PutMetricData を定期送信する場合、送信間隔は CloudWatch の Period より少し短く設定するのが実務上の定番。公式のベストプラクティスとして明文化されてはいないが、タイマーのドリフトを考慮すると必要な対応。