この記事は ドワンゴ Advent Calendar 2025 10日目の記事です。
はじめに
こんにちは、ギフト・ニコニ広告開発チームの@brpと申します。
今年はギフト・ニコニ広告システムのアプリケーションログの集約・分析基盤としてCloudWatch Logsから脱却し、Firehose+S3+AWS Glue+Athenaによるシステムへの移行を行いましたので、その紹介させていただきます。
前提
前提として、AWS移行後のニコニ広告のアプリケーションログは以下のような構成で扱っていました。
アプリケーションインスタンスから発行されたログは、CloudWatch AgentによってCloudWatch Logsへ集約され、開発者はここで抽出・分析をすることができます。
また、一部のログはFirehoseでS3に転送され、そこから別のシステムにフェッチされ数値集計へ送られます。
CloudWatch Logsの機能で必要なものがすべて完結するシンプルな構成でした。
実施の経緯
そもそも、なぜここからCloudWatch Logsを脱却する必要があったかなのですが、純粋にログ取り込みのコストが巨大になっていたためでした。
ニコニ広告のシステムのログはとても多く、その量は月間数TBに上ります。
これは、ニコニ広告が動画・生放送・静画・大百科・立体…などニコニコファミリーサービスに跨って提供されているサービスであり、なおかつ各サービス内で広告枠という形で露出する機会が多いためです。
これらは、ひとつはアクセスログという形で現れ、積み重なっていきます。
ある程度は予想できていた分ではありましたが、この時のコストはニコニ広告の利用するAWSサービスのうち、一二を争うレベルまで膨れ上がっていました。
それでも費用に対する恩恵があればよかったのですが、このサービスコストは障害発生時の復旧対応や、サポートに頂いた連絡に対する調査程度しか直接的なユーザーへの還元にはつながらず、見直す方針となりました。
技術選定・検討
新たなログ基盤を検討するにあたり、以下の要件は必須でした。
- CloudWatch Logsを使用した際よりコストが削減できること
- ログの完全性が保てること
- 集約が可能であること
- 分析が可能であること
必須要件
CloudWatch Logsを使用した際よりコストが削減できること
これは当たり前なのですが、CloudWatch Logsのコストを削減したいのに、それ以上のコストが掛かっていては本末転倒となってしまいます。
ログの完全性が保てること
ニコニ広告のシステムが発行するログは、開発的なエラーログやデバッグ情報のほかにも、アクセスログなど一定期間保管が必要なログや、数値集計に利用される情報など非常に重要なログが存在しています。
それらは絶対にロストしてはなりません。
集約が可能であること
CloudWatch Logsを辞めたいだけであればアップストリームを廃止して、障害時や調査などはSSHでログファイルをgrepする運用とすることで解決します。
しかし、ニコニ広告のアプリケーションはステートレスな仕組みとなっており、
例えばニコニ広告する画面を開いた際と実際に「ニコニ広告する」ボタンを押してニコニ広告した時に処理されるアプリケーションのインスタンスが同一とは限りません。
そのため、インスタンス単位ではログの連続性は失われ、なおかつトレースしたいユーザーのアクションがどのインスタンスに振り分けられたかは分からず、障害調査が困難になってしまいます。
また、ニコニ広告のアプリケーションインスタンスは全体の負荷を見て自動的に水平方向にスケールされます。
拡張されたインスタンスは負荷が落ち着いた際に削除され、適正な台数に縮退されます。
そうなったとき、削除されたインスタンスの内部のデータも削除されてしまうため、後から調査の必要が出た際、ログが失われてしまい追跡ができなくなってしまいます。
そのため、ログは外部へ取り出し、集約できる仕組みが必要となります。
分析が可能であること
これは、必須ではありませんが無いととてもしんどくなってしまいます。
先述した通り、ニコニ広告のアプリケーションログは非常に大量です。
その中から目的のログを探し出すには、目視では至難の業となってしまいます。
そのため、目的のログを抽出できる仕組みは必要となります。
最終的なアーキテクチャ
最終的な構成は以下の通りです。
アプリケーションから出たログは、FluentdによりFirehoseへストリームされます。
Firehoseはログを種類ごとに集約し、一定量溜まったらS3へ転送します。
S3に溜まったログは、AWS Glue Crawlerが走査しインデックスをAWS Glue Datacatalogへ登録します。
これで、実データがS3、それに対応するスキーマ情報・インデックスがDatacatalogに存在するため、Amazon Athenaによる効率的な抽出・分析が可能になります。
また、アプリケーションが吐くログはJSON構造化されているため、タイムスタンプなどの各項目をカラムとして扱い抽出することができます。
なぜアプリケーションインスタンスからS3へ直接配置しなかったのか
分析はAWS Glue+Athenaで実現するため、S3に直接ログファイルを転送すればFirehoseのコストも掛からず要件を実現できるはずです。
こうしなかった理由は、先にも述べたニコニ広告のスケールの仕組みにあります。
ニコニ広告のアプリケーションインスタンスは、全体的な負荷を見て水平方向にスケールされます。
負荷が落ち着いた際はアプリケーションインスタンスが削除され、縮退されることで適正なスペックに戻されるのですが、
S3にログファイルを直接配置する際はある程度の時間アプリケーションインスタンス内部でバッファを持たなくてはなりません。
そうなった際、次回の転送までの間に縮退が決定され、インスタンスが削除されてしまうとその間のログはロストしてしまうことになります。
また、マシンそのものが何らかの事情でハングする恐れもあり、内部で稼働するエージェントも稼働できなくなる可能性があります。
そうなった際、長い期間ログをため込んでいるとロストしてしまう量が大きくなってしまいます。
そういったリスクを避けるため、可能な限りアプリケーションインスタンス内部でのバッファを短くし、外部の安全な場所に退避させるようFirehoseへのストリームを行っています。
コスト削減効果
ニコニ広告のログにかかわるコストは、移行前から移行後でおよそ1/3へ削減されました。
移行後のコストとして発生しているものは、主にFirehoseへのデータ取り込みコストとなります。1
CloudWatch Logsのログ取り込みコストは、USD 0.76/GBです。2
Firehoseのデータ取り込みコストは、USD 0.036/GBです。3
データの取り込みコストそのものの差はおよそ20倍ですが、実際のコスト差はそうなっていません。
これは、Amazon Data Firehose 料金の注釈にある以下の文の通り、
Firehose ストリームの基本機能は取り込みと配信です。取り込みの料金は階層別であり、5 KB 単位で取り込まれた GB ごとに請求されます (3 KB のレコードは 5 KB、12 KB のレコードは 15 KB として請求されるなど)。オプション機能を使用しない限り、配信に Data Firehose の追加料金はかかりません。
Amazon Data Firehoseはデータ量をレコード単位で勘定し、5KB単位で切り上げて計算しているためです。
CloudWatch Logsが計算している実際のデータサイズよりも大きなデータ量で計量されることにより、圧縮効果は期待よりも薄くなっています。
最後に
アプリケーションログの転送先として、CloudWatch Logsを使用している方は少なくないかと思います。
CloudWatch Logsのログ取り込みコストは、USD 0.76/GBと、AWSの他サービスのコストと比較しても高額です。
今回のケースでは、一定データ量を超える割引などに頼ったコスト削減などではないため、ある程度普遍的に使える構成かと思います。
もしこの記事が同じ悩みを抱えている方の参考になればとてもうれしく思います。
-
ほかにも、Glueの料金やAthenaのクエリ料金やS3のデータ保管料金などが掛かりますが、Glueは一日一回のクローラー稼働と30テーブル程度のメタデータの保管では無料枠に収まる程度であったり、Athenaのクエリも1TBの走査で5 USDとほぼ誤差のような値となっています。 ↩
-
Amazon CloudWatch 料金表より https://aws.amazon.com/jp/cloudwatch/pricing/ ↩
-
Amazon Data Firehose 料金より https://aws.amazon.com/jp/firehose/pricing/
Fluentdから送信する場合、送信元はDirect Putとなります。送信先にS3バケットを指定する場合は「その他の送信先」となります。 ↩

