
はじめに
カミナシの共通ID管理基盤を開発しているmanaty(@manaty226)です。カミナシ ID管理基盤ではログストレージにCloudWatch Logsを使っていましたが、サービスの成長に伴いコストに悩んでいました。この記事では、私たちが実践したAmazon S3 Tables(以下、S3 Tables)を使ったログストレージの構築と移行、そのコスト最適化効果について書きます。
サービス成長に伴うCloudWatch Logsのコスト増大
Amazon CloudWatch Logs(以下、CloudWatch Logs)はAWSが提供するログの保管や分析のためのサービスです。多くの一般的な構成ではアプリケーションが出力するログをそのままCloudWatch Logsに保管し、何かあればCloudWatch Logs Insightsを利用してログをクエリしたり、特定のエラーログにもとづくアラート設定をCloudWatch Alermと連携して行っているかと思います。私たちのID管理基盤も同様に、ECSからログルーターを介してCloudWatch Logsへログを配信し、Amazon Managed Service for Grafana(以下Grafana)を使って日々の開発運用に役立てていました。
一方で、カミナシのサービスが成長するにつれて、全てのサービスの認証認可リクエストを捌くID管理基盤は、そのリクエスト数の増大や機能拡張に伴ってログコストも無視できないほど膨らんでいきました。週次で行うレビューにより不要なログを排除したりまとめることで地道に改善できた部分もありますが、そういった改善活動では大幅なコスト最適化は難しく、抜本的な対策を考え始めました。

通常運用するうえで発生するCloudWatch Logsのコストには大きく、ログの取り込み、保管、クエリの3つがあります。料金表からも分かるように、コストが膨らむ主要因はログの取り込みであるため、どれだけ保管期間などを最適化してもリクエスト数の増大に比例してログコストも大きくなっていくことが分かりました。
そこで、コストと運用の両面でバランスが取れそうなS3 Tablesへログを取り込み保管することを検討しました。
Amazon S3 Tablesへの移行
S3 Tablesとは
S3 Tablesは、Apache Icebergというオープンなテーブルデータフォーマットを実装したAWSサービスです。下図に示すように、Icebergではデータの実体となるIceberg形式のファイルに対してメタデータを管理することで、Amazon AthenaやSparkといったクエリエンジンからテーブルデータとして読み書きすることができます。メタデータによってテーブル構造が抽象化されているため、パーティションやカラムなどのテーブルスキーマの変更に柔軟であったり、スナップショットして管理されているメタデータ変更履歴に基づき過去のデータを読み出せるタイムトラベル機能、他にも従来のデータレイクハウスで利用されてきたHiveフォーマットの課題を解決しています。詳細は公式ページや、「実践Apache Iceberg」や「Apache Iceberg活用入門」といった書籍を読むことをおすすめします。
CloudWatch Logsのようにスキーマの事前定義なくクエリ時に柔軟にデータを読み込むことはできないものの、S3 Tablesにより馴染みのあるSQL構文を使って検索できることや、S3の安価なストレージを利用することによるコストメリット、コンパクションのようなIcebergの日々の運用をマネージドサービスに委任できること、将来的なスキーマ進化によるログ構造の変化への追従性などを鑑みてS3 Tablesへ移行することにしました。

ログ配信パイプラインによる段階的な移行
事前にCloudWatch LogsからいくつかのログをサンプリングしてS3 Tablesに投入し検証を行ったものの、実際に運用の中でどこまで現実的に使えるか分からなかったので、以下のような手順で段階的に移行しました。
- ECSから配信されたログをログルーターで受けた後、ログルーターからCloudWatch LogsとAmazon Data Firehose → S3 Tablesの両方にログを配信
- 監視ツールとして利用しているGrafanaのクエリ先をS3 Tablesに変更して日々の運用における使用感や課題を洗い出し
- S3 Tablesによる運用が問題ないと判断できた時点で、ログルーターの配信先をS3 Tablesへ変更(ただし、エラーログはアラートにも利用しているため引き続きCloudWatch Logsへ配信)
これにより、仮にS3 Tablesが私たちの運用に利用することが難しいと判明しても、CloudWatch Logsに保管されるログは引き続き欠損することなくクエリできるので、安全に移行することができました。

S3 Tables移行後のコスト最適化効果
CloudWatch Logsへのエラーログ以外のログ配信を停止してから、すぐに大幅なコスト最適化効果が見られました。コストの主要因であったログの投入にかかるコストは8割以上削減され、クエリコストもCloudWatch InsightsからAthenaに変わったことで大幅に低減しました。

S3 Tablesと周辺エコシステムにおける現在の技術制約
S3 Tablesのパーティション変更
S3 TablesのパーティションはAthenaから変更することができません。したがって、作成時に設定したパーティション設定から変更したい場合は、そのためにAWS Glueジョブを使ってSparkクエリを書いてパーティション変更を行ったり、その他IcebergクライアントからDDLを実行する必要があります。せっかくAthenaというマネージドクエリサービスがあるので、ここは改善してほしいと思っており今後に期待しています。
Intelligent Tieringの利用開始可能タイミング
S3 TablesはCloudWatch Logsに比べるとストレージコストが低いものの、毎日ログが蓄積されていけばコストは日々増加します。S3 Tablesは2025年12月に発表されたIntelligent Tieringにより、規定の期間アクセスされていないファイルのストレージクラスを自動的に最適化される機能を持っています。適切なパーティションが存在すれば、例えばログについては多くの場合直近のログにアクセスパターンが偏るため、古いログのストレージクラスが変更されてさらなるコスト最適化効果が見込めます。
一方で、Intelligent Tieringはテーブル作成時しか設定できず、標準ストレージで作成されたテーブルを後から変更することはできません。殆どの場合はIntelligent Tieringで良いはずなので忘れずに設定しましょう。私たちは泣きながらテーブルを再作成しました。
Terraformによる構築時の注意事項
カミナシではAWSインフラ管理にTerraformを利用しています。hashicorp/terraform-provider-awsが提供するモジュールには大変お世話になっていますが、S3 Tables周辺のAPIパラメータはまだまだ対応していないものも少なくありません。例えば、前述したテーブル作成時のパーティション設定やIntelligent Tieringの設定についても、PRはオープンしているもののマージはされていません。以前私が出したAthenaのマネージドクエリリザルト対応のPRもマージまで3か月ほどかかったので、これらの機能を欲している皆様はPRに👍してメンテナにIcebergへの熱い思いを伝えましょう。
おわりに
今回はアプリケーションログストレージをCloudWatch LogsからS3 Tablesへ移行してコスト最適化した事例紹介をおこないました。CloudWatch Logsは非常に使いやすく始めやすいため、アプリケーション開発の初期には私も毎回必ずCloudWatch Logsを選択します。その一方で、アプリケーションの成長とともにログコストは肥大していきます。そんなときに、S3 Tablesをログストレージの選択肢のひとつとして考えてみてはどうでしょうか。
私は昨年Icebergの書籍を読んでから、そのメタデータアーキテクチャやコンパクション戦略を基に、IoTデータような小さなデータを逐次的に投入するユースケースから大量のデータをバッチ的に取り扱うユースケースまで幅広く対応しようとする仕様の面白さに感銘を受けています。
カミナシでは、Apache Icebergを生きがいとして世の全てを解決するソフトウェアエンジニアも募集しています。興味がある方はカジュアル面談からお願いします。
