3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CloudWatch Logsのコストを約7割削減した話

Posted at

はじめに

上司から「担当サービスのCloudWatch、コストが高いから見直して」と言われました。
確認してみると、ECS(PHP/Apache)で運用しているサービスのCloudWatch請求が月数十万円。
「こんなに高くなるのか…」というのが第一印象です。

何から手をつければいいか分からなかったので、まずコストの内訳を調べるところから始めました。
本記事では、その調査からコスト削減するまでの流れを紹介します。

調査・対応の流れ

どのログを削減すれば効果があるか分からなかったので、まずコストの内訳を見て原因を特定し、そこから不要なログを削減しました。

  1. Cost Explorerでコストの内訳を確認する
  2. 取り込み量が多いロググループを探す
  3. 該当のロググループ内で不要なログを探す
  4. 不要なログを削減する
  5. 効果を測定する

Step1:Cost Explorerでコストの内訳を確認する

Cost Explorerで下記を設定します。

  • Service:AmazonCloudWatch
  • Group by:Usage type
Usage type 割合
APN1-DataProcessing-Bytes 約98%
APN1-TimedStorage-ByteHrs 約2%

請求の約98%が取り込み(DataProcessing-Bytes)でした。

保存(TimedStorage)は全体の1〜2%程度なので、保持期間を短くしても効果は薄そうです。
そのため、取り込み量を削減する方針で進めました。

補足:Usage typeの見方
Cost ExplorerのUsage typeは「リージョン接頭辞 + 課金カテゴリ」で表示されます。
CloudWatch Logsでよく見るカテゴリは次のとおりです。

DataProcessing-Bytes:ログ取り込み(Operation: PutLogEvents)
TimedStorage-ByteHrs:ログストレージ(Operation: HourlyStorageMetering)
DataScanned-Bytes:Logs Insightsのスキャン(Operation: StartQuery)

Step2:取り込み量が多いロググループを探す

ロググループごとの取り込み量はCloudWatch Logsのメトリクス(IncomingBytes)で確認できます。
参考:AWS re:Post - Determine which log group is causing a bill increase

マネジメントコンソールで確認する手順

  1. CloudWatchコンソールを開く
  2. 左メニューで「メトリクス」>「すべてのメトリクス」を選ぶ
  3. 名前空間の一覧から「Logs」>「ロググループメトリクス」を選ぶ
  4. 検索ボックスに「IncomingBytes」と入力してフィルタ
  5. 該当サービスのロググループにチェックを入れる
  6. 「グラフ化したメトリクス」タブを開く
  7. グラフの設定を下記に変更する
    • グラフの種類:数値
    • 統計:合計
    • 期間:30日

これで取り込み量が多いロググループを特定できます。

ロググループごとの集計

Step3:該当のロググループ内で不要なログを探す

コストを抑えるにはログの取り込み量を削減する必要があります。
Step2で特定したロググループに対し、Logs Insightsで出力回数が多いログ、またはサイズの大きいログを探します。

Logs Insightsはスキャン量に応じて課金されるため、今回は3日間に絞って調査しました。
コストを抑える方法は記事末尾の補足にまとめています。

出力回数が多いログを探すクエリ

今回はmsgフィールドでグルーピングしました。
ログの種別を判別できるフィールドであれば、levelactionなど他のフィールドでもOKです。

fields msg
| filter ispresent(msg)
| stats count(*) as lines by msg
| sort lines desc
| limit 50

上位に表示されやすいログの例:

  • リトライ・ループ内で出力されるログ
  • 定期処理の「開始/終了」ログ
  • 正常系でも毎回出力されるアクセスログ・処理完了ログ

サイズの大きいログを探すクエリ

出力回数が少なくても、1行あたりのサイズが大きいとコストに影響します。
msgごとに@messageの文字数合計を算出し、大きい順に並べます。

fields msg, @message
| stats
    count(*) as lines,
    sum(strlen(@message)) as bytes_est,
    avg(strlen(@message)) as avg_line_size
  by msg
| sort bytes_est desc
| limit 50
カラム 説明
lines 出力回数
bytes_est 文字数合計(取り込み量の目安)
avg_line_size 1行あたりの平均文字数

avg_line_sizeが大きいログは、巨大なペイロードを含んでいる可能性があるので見直した方が良いかもしれません。

Step4:不要なログを削減する

Step3で候補を出せたら、不要なログを削減します。
削減対象とする基準と、今回実施した具体的な対応を記載します。

削減対象の基準

項目 説明
debug/trace系 調査には便利だが、本番で常時出力するとコストが増加する
ループ・リトライ内のログ 1行あたりが小さくても、総量が増える
巨大ペイロード リクエスト/レスポンス本文や巨大スタックトレースなど

今回実施した対応

  1. ログレベルの変更
    • PHPのログレベルをDEBUGからWARNに変更
      • 調査のためにログレベルを上げたまま戻し忘れていた箇所
  2. ループ内ログの集約
    • 1件ごとに出力していた処理完了ログを、処理件数のサマリーログ1行に集約
  3. 巨大ペイロードの改善
    • レスポンスボディをログ出力していた箇所を、調査に必要なフィールドのみ出力するよう変更

Step5:効果を測定する

Step4の対応後、Cost ExplorerでDataProcessing-Bytesの推移を確認したところ、約7割のコスト削減を達成できました。
今回の削減、ほとんどがログレベルの戻し忘れによるものでした…。
調査でDEBUGに上げたまま放置していただけで、これほどコストが膨らんでいたとは思いませんでした。

「ログくらい大したことない」と思いがちですが、調べてみると意外と無駄は見つかります。
やはり定期的なコストの見直しは大事ですね。

まとめ

CloudWatchのコストが高い場合は、以下の手順で対応します。

  1. Cost ExplorerのUsage typeで内訳を確認する
  2. CloudWatch Logsは保存より取り込みが高いケースが多いため、取り込み量の削減を優先する
  3. Logs Insightsで不要なログ(出力回数が多い・サイズが大きい)を特定し、削減する

今回は不要なログの削減でコストを抑えることができましたが、まだ改善の余地があるので少しずつ進めていきたいですね〜

補足:Logs Insightsのスキャンコストについて

Logs Insightsのスキャンは圧縮前のデータ量に対して課金されます。(東京:0.0076 USD/GB)
例えば、調査に必要な期間が3日で十分なのに1週間に設定し、スキャン量が500GBになった場合、0.0076 × 500 = $3.8(約600円)かかります。

1回あたりの金額は小さくても積み重なると結構痛いため、

  • スキャン期間を必要最小限にする
  • フィールドインデックス機能を使用する

などの対策をするのがオススメです。

参考:フィールドインデックスの公式ドキュメント

3
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?