freeeの開発情報ポータルサイト

「私たちのログ配送、コストかかりすぎ?」fluentdのログ配送に関するコスト削減に取り組んだお話

はじめに

こんにちは!freee のPlatform Engineerをやっているyamaです。 私の所属するCloudGovernance(CGov)チームでは主にAWS関連の権限やコストの統制・可視化・最適化などを行っています。 私は主にコスト統制をメインに担当しています。

この記事はfreee Advent Calendar 2025の7日目になります!

今回はfreeeにおけるコスト最適化において大きな成果のあった、「fluentdのログ配送に関するコスト削減」についてご紹介いたします。

背景

CGovチームではAWSのコスト可視化・最適化を進めており、AWSのコストを定期的に確認しています。 ある日、AWSのコストエクスプローラを確認していたところログに関連するS3バケットコストの内訳に違和感を覚えました。何気なしにグラフにしてみたところ以下のようになりました。

グラフからもわかるように、明らかにRequests-Tier2のコストが大きい事がわかります。

Requests-Tier2については後ほど述べますが、基本的にはリソースの要求であるGetObjectなどが含まれます。 もしこのバケットがアセットや顧客が利用する画像などのデータであれば、それなりに呼び出されることはあるでしょうが、今回の対象はログ関連のバケットです。 ログですので、セキュリティや監査目的でいくらかデータを読み込んでいる可能性もありましたが、それを考慮しても明らかに過剰なコストです。対象のバケットには8年以上前からログが投入され、EKS移行からは4年ほど経過していますから、これまでに相当のTier2関連のAPI Callがされていることになります。

S3におけるコストに関して

AWSのS3では保存データ量に応じて発生する料金、API Call料金、転送料金、データ管理コストなどの料金が発生します。

そのうちAPICallのTier1とTier2はAWSでは以下のように定められています

Requests-Tier1 : S3 Standard、RRS、タグに対する PUT、COPY、または POST リクエストに加え、すべてのバケットとオブジェクトに対する LIST リクエストの数

Requests-Tier2 GET および他のすべての Tier1 以外のリクエストの数

Requests-Tier2はS3 API CallのGETおよびRequests-Tier1のPUT/COPY/POST/LIST以外が含まれます。 Requests-Tier2よりも詳細な内訳コストを確認するためにはCost and Usage Report(CUR、コストと使用状況レポート を利用する必要があります。 freeeではCURデータを一定期間保持しており、Tier2の内訳のコスト詳細まで追うことができます。

CURを利用して取得した2025年2月-3月のHeadObjectとPutObject、そしてGetObjectのグラフは以下のようになります。

右軸と左軸では比率が異なりますが、左軸が右軸の数倍となっています。 PutObjectとHeadObjectの2つのデータには非常に強い正の相関(ρ=0.995)があることがわかりました。 GetObjectのAPICallは基本的にはあまり行われておらず、何かしらの調査が行われた際に小さな山(3/13付近および3/17)が発生していることもわかります。

この結果からログの配送であるPutObject(アップロード)とHeadObjectとの関連を疑いました。

原因

原因に悩んでいたある日、とある記事にたどり着きました。

www.greptips.com

qiita.com

freeeではアプリケーションから吐き出したログを2系統で配送しています。 1つはdatadogへ配送しており、Engineerがリアルタイムでログを確認することができます。 もう1つは、長期保存を目的としてS3へ配送します。

この内S3への配送ではfluentdを利用しており、どういった経緯かは不明ですが、検証環境も含めた全環境・全プロダクトに対してcheck_object: trueの設定が入っていました。また、ログ欠損の対策と思われますがfluentdのログ配送間隔が非常に短かったことも相まってHeadObjectのCall数が極端に大きくなりました。

詳細については参考文献に譲りますが、check_objectが有効な場合はアップロード前にS3に対してアップロードファイルが存在するかを確認します。存在する場合はindex idを+1し、再度確認を行う…という動作をファイルが存在しなくなるまで繰り返します。

check_object有効時におけるFluentdの処理フロー(index id=0の場合)

check_object有効時におけるFluentdの処理フロー(index id=100の場合)

対応

対応方法についてはcheck_objectをfalseにすることですが、それだけではファイル名衝突を起こし上書きが発生してしまいます。この対応としてファイル名末尾にあったindex idをhhmmssのタイムスタンプを利用することにしました。

check_objectオプション無効時のFluentd処理フロー
ファイル名の前半にはpod名を利用しているため、基本的に名前衝突が発生する可能性は低いですが、万が一衝突した場合もバケットバージョニングにより元ファイルの保持が可能です。

検討事項

check_object: falseにするためにいくつかの検討を行う必要がありました

  • ログファイル名の変更によってバッチ処理などに影響が出ないかの調査
  • エッジケースにおけるログ利用に影響が出ないか

これらについては各Productチームや所管チームへ確認の依頼をお願いし、必要であれば修正をお願いしました。

コスト削減効果

全環境への導入作業には様子見の期間も含めてざっくり1ヶ月程度かかりました。

Requests-Tier2の月次コスト推移
設定の見直しの結果、グラフから分かるように上昇トレンドだったRequests-Tier2のグラフは9月を境にほぼ消滅しました。割合としてはログバケットで発生していたHeadObject APICallの99%以上を削減することができました。

現在のとあるログバケットのコスト割合は以下のようになります。

HeadObjectコスト削減後のコスト割合
冒頭で半数以上を占めていたRequests-Tier2は分析コスト未満になりました。分析コストもデータ集計頻度の見直しにより削減されたようです。

最後に

ログ配送でよく利用されるfluentdの設定であるcheck_objectの見直しにより大きなコスト削減を得ることができました。技術的に新しいことはありませんでしたが、個人的にはコストにおける「塵が積もれば山となる」の典型的な例だと思っていますので、コスト削減に取り組む皆様の一助になればと思います。

またこの場を借りまして改めて今回のコスト削減を助けてくれましたチームの仲間、相談に乗ってくれた・ご対応していただいた皆様に感謝いたします。

freee Advent Calendar 2025の8日目は Akira KUSAMAさんの『Copilotのプロンプトだけでアルバムアプリを作ってみた話』となります!ぜひこちらも見てくださいね!

ちょっとした宣伝

ログ関連では、zaki3によるvectorの記事もありますのでぜひご覧ください

Vectorの魅力を語る!ログ収集ツールとしての可能性を語りたい - freee Developers Hub

CGovチームの過去の記事はこちら、もしお時間あればぜひ見てみてください!

AWS の組織移行をしました - freee Developers Hub

年末大掃除と来年の抱負(AWSの大掃除とfreeeのFinOpsの未来) - freee Developers Hub

AWS のコスト統制の道 - freee Developers Hub