Web APIのログ保存先をCloudWatch LogsからS3に変更してコストカットした話


Loading...


KADOKAWA Connected Integrated Data Service部の中沢です。

私の部署ではイベントを記録するためのWeb APIを開発・運用しています。

engineering.kdx.co.jp


ブログ公開時は既存Web APIから新規Web APIへの利用移行が始まった段階でしたが、先日移行が無事完了しました。

その中で、アクセス数の増加によりCloudWatch Logsに保存するアクセスログのコスト問題の対応を行いましたので、本ブログではその対応に関して紹介します。

大量イベントを記録するWeb APIが必要になった背景

今回、大量イベントを記録するWeb APIの開発が始まったのは、既存のWeb APIがオンプレミス環境で動作していたのをクラウド環境に移す必要が出てきたためでした。

既存のWeb APIからの移行であるため、簡単な案件といいたいところですが、本システムの開発には以下のような制約が存在していました。

  • 既存のWeb APIは月間で数十億リクエストを処理しており、同等のリクエストを処理できるWeb APIを構築する必要がありました
  • 既存のWeb APIと同レベルかそれ以下の費用で運用できる必要がありました

したがって、下手なWebサービスよりもアクセス量が多そうなWeb APIを、オンプレミス環境より安価にクラウド環境上で構築する必要がありました。

Web APIシステムのアーキテクチャ

本システムのアーキテクチャは以下の通りになっています。

Web APIシステムのアーキテクチャ

ALBでリクエストを受け、アプリケーションコンテナ (ECS Fargate) で処理を行います。

アプリケーションコンテナより、AWS Firelensを利用してFluentbitに送信します。Fluentbitは受け取ったデータの内容に応じて、データを以下のように振り分けます。

  • データ分析のためにイベントはKinesis Data Streamsに送信
  • システム運用のためにアプリケーションコンテナのアクセスログ・アプリケーションログはCloudWatch Logsに送信


CloudWatchは、(使いにくい部分もありますが...) システムの運用をしていく中で必要となる多くの機能を有している点が良いところです。また、AWSの他サービスと連携しやすい点も魅力的です。

本システムでは、CloudWatch Logsに取り込んだアクセスログを利用して、以下のような運用を行っていました。

  • CloudWatch Logs Insightsを利用したクエリによるログ分析
  • CloudWatch Metric Filter + CloudWatch Dashboardを利用した可視化
  • CloudWatch Metric Filter + CloudWatch Alarmを利用した監視

CloudWatch Logsのアクセスログを利用した運用構成

発生した問題

システムリリース数ヶ月後、問題になってきたのはCloudWatch Logsのログ取り込み料金でした。

2023年12月現在、ap-northeast-1においてCloudWatch Logsのデータ取り込み料金は0.76USD/GBであり、例えば1TB取り込んだ際には760USD (1USD150yen換算で114,000yen) かかります。取り込みログ量が多い場合、CloudWatch Logsの料金が高くなりがちです。

前述の通り、本システムはアクセス数が多いWeb APIとなっています。またコスト的な制限も存在します。

そのため、アクセス数の増加に伴う取り込みアクセスログ容量の増加により、CloudWatch Logsのログ取り込み料金が看過できなくなりました。

問題への対応

CloudWatch Logsのアクセスログ取り込み料金問題に対応するために、CloudWatch Logsから別の何かへ保存先を変更する必要がありました。

また、CloudWatch Logsに保存したアクセスログに対してCloudWatchの機能を利用した分析・可視化・監視を行っていたため、アクセスログ保存先変更後もそういった運用を可能な限り継続して行えるようにする必要がありました。

保存先の変更

アクセスログの保存先をCloudWatch LogsからS3へと変更しました。

試算の結果、CloudWatch Logsへのログの取り込みと比較し、S3での取り込みは格段に費用が安くなりそうだったためです。実際格段に安くなりました。 (取り込み料金にだけフォーカスすると99%ほどコストカットできています *1

以下のようにFluentbitのS3 output pluginを利用してS3にアクセスログを直接送信する方針に切り替えを行いました。

新Web APIシステムのアーキテクチャ

S3に送信する際にKinesis Data Streams・Kinesis Data Firehose等を噛ませるような構成も考えられます。一般的にKinesis系のサービスはストリーミング処理に向いているため、Fluentbitから直接S3に送信するよりもKinesisを挟んだ方が安定してデータをS3に配信できると思われます。

しかしKinesisを利用する分料金がかかるため、負荷試験で問題が発生しないことを確認した上で、コスト重視で本構成を採用しました。

運用の変更

アクセスログの格納先の変更に伴い、以下のような運用変更を行いました。

変更前 変更後
ログの分析 CloudWatch Logs Insights Athena
ログの可視化 CloudWatch Metric Filter + CloudWatch Dashboard QuickSight
ログを利用した監視 CloudWatch Metric Filter + CloudWatch Alarm -

S3に保存したアクセスログを利用した運用構成

ログの分析には、S3に保存したデータをクエリで手軽に分析可能なAthenaを採用しました。

ログの可視化には、Athenaと連携してS3のデータの可視化が可能なQuickSightを採用しました。QuickSightは利用人数ベースの課金体系なため、大規模なシステムで大人数の運用を行っている際にはコスト的な問題が発生するかもしれません。しかし本システムの運用チームは小規模なため、コスト面の問題はありませんでした。

ログの値を利用した監視は、S3のデータを利用した新たな監視システムの構築は複雑になりそうであったため断念しました。代わりに別のAWS標準のメトリクスを利用した監視で代用しました。

小噺

S3のオブジェクトサイズとFluentbitのトレードオフ

Fluentbitは、ある程度の大きさのデータをまとめて一つのオブジェクトとしてS3に送信します *2

Fluentbitでどの程度データをまとめてS3に送信するかに関して、いくつかの評価観点が存在します。

  • Fluentbitの目線では、なるべく早くデータを追い出したい (ためオブジェクトを小さくしたい)
  • Athenaの目線では、一つ一つのオブジェクト容量が128MB程度であることが望ましい *3
  • 料金の目線では、S3へのリクエスト数は可能な限り減らしたい *4 

等です。


検証・試算を行い、FluentbitからS3に5MB程度のオブジェクトを送る方針であっても

  • Athenaでクエリを実行しても運用で耐えないほどの実行時間にはならない
  • FluentbitからS3へのリクエスト数を見積もり、S3の取り込み料金を試算しましたが、CloudWatch Logsの取り込み料金よりはるかに安い

ことを確認しました。

今回はなるべく早くFluentbitから追い出せるよう5MBに設定しました。

Athena + QuickSight料金の話

新構成では、Athena+QuickSightを利用してデータの可視化を行います。

前述の通り、非常にアクセスが多いシステムなため、アクセスログの容量も大きくなっています。

そのため雑にQuickSightで可視化を行おうとすると、Athenaが裏でデータを総舐めし、コストが爆発する *5 恐れがあります。


この問題に関しては、以下の対応を取りました。

  • Athenaで日付ベースのパーティショニングを行う*6
  • QuickSight可視化時に必要なデータのみAthenaが読み込むようにパラメータで日付指定する*7


以下のようにQuickSight可視化時に、読み込みたい時間区間をパラメータとして与えることで、その区間のデータのみAthenaで読み込むように制限します。実行されたAthenaのクエリを確認すると、指定したパラメータの値でフィルタリングしていることが確認できます。

パラメータで表示する時間区間を絞ったQuickSightのグラフ

QuickSightが実行したAthenaのクエリのwhere文箇所

頻繁にダッシュボードを確認する際には、(見たい時間区間を指定する必要があるため) 一手間かかる点が面倒ではあります。しかし、運用で利用する分には確認頻度はそれほど高くないため、問題ないと判断しています。


また、Athenaのワークグループを利用した安全弁も設けました。ワークグループを指定することで、Athenaのクエリの読み込み容量が閾値を超えるとクエリが失敗するようになります。

クエリが失敗した場合、QuickSightでは以下のようにデータが表示できなかった旨が出てきます。また、裏側で走っているAthenaのクエリの実行結果を確認すると、ワークグループの制限によりクエリが失敗したというメッセージが表示されます。

ワークグループの読み込み制限に引っかかった際のQuickSightダッシュボード

ワークグループの読み込み制限に引っかかった際のAthenaクエリの実行結果

まとめ

CloudWatch Logsに保存していたアクセスログを、S3に保存するようにすることで取り込みコストを削減したという内容でした。

(大量イベントを記録するWeb APIの設計から実装まで - KADOKAWA Connected Engineering Blogのまとめでも触れておりますが) 設計・開発の中で行なってきた判断が正しかったかどうか、日々の運用の中で評価し、改善を行なっていくことが重要だと思います。

今後もコストの問題への対応等、システムがより良いものになっていくよう改善を行なっていきたいと考えています。

*1:Cost Explorerで確認できるCloudWatchの取り込み料金にあたるDataProcessing-Bytesと、S3のput等のリクエストに関する料金にあたるregion-Requests-Tier1 (regionはS3の存在するAWSのリージョン) のコストに関して、変更前後の比較を行いました。 https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/cloudwatch_billing.html https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/aws-usage-report-understand.html

*2:マルチパートアップロード方式も存在します。負荷試験で検証を行いましたが、動作が不安定だったため今回は採用を見送りました。

*3:オブジェクトが128MB未満である際にAthenaのクエリのオーバーヘッドが大きくなり、Athenaのクエリ実行時間が延びるそうです。https://aws.amazon.com/jp/blogs/news/top-10-performance-tuning-tips-for-amazon-athena/

*4:S3へのデータ取り込みは、S3へのリクエスト数ベースの課金になります。

*5:Athenaはクエリ実行時の読み込み容量に料金が依存するためです。

*6:Athenaでクエリ実行時に読み込むデータ範囲を制限することができます。https://docs.aws.amazon.com/ja_jp/athena/latest/ug/partitions.html

*7:データセットパラメータに読み込む日付を指定したカスタムSQLのデータセットを用意しました。 https://aws.amazon.com/jp/blogs/news/optimize-queries-using-dataset-parameters-in-amazon-quicksight/