本記事は CyberAgent Advent Calendar 2022 23日目の記事です。

 

「節約は固定費から。」 こんにちは、しゅん(@MxShun)です。
今年11月に中途入社、AI事業本部オペレーションテクノロジーに仲間入りしました。

今回は、年間にして 1,200 万円削減 した Amazon S3 のコストカット全ステップ を紹介します。

 

目次

 

オペレーションテクノロジー

オペレーションテクノロジー

私がジョインしたオペレーションテクノロジーは、

  • サイバーエージェント 連結売上高の53%(2022年通期決算時点)を占めるインターネット広告事業売上を最大化する システム開発
  • 大規模インターネット広告運用を可能にする 社内システム開発

の役割を担っています。

具体的なシステムに、企業が保有する自社の商品データに基づき各広告配信先の仕様にあわせ最適化したデータフィードを生成する「CA DataFeed Manager」や、広告入稿時に不承認となった商品データの特定から修正までを自動化することでインプレッション数を最大化させるサービス「GMC Maximizer」があります。詳しくは弊社プレスをご覧ください。

 

AWSコストの見直し

今回ターゲットのシステムでは、システム構築やデータ永続化のほぼすべてに AWS(Amazon Web Services)を利用しています。そして、上で述べた通り大量のデータを大規模運用で扱う特質上、莫大な AWS コスト が毎月かかっていました。

ローンチから数年経ち安定した本番稼働ができているシステムも多いことから、改めて AWS コストを見直しました。

AWSコスト サービス別内訳

上はある月の請求ダッシュボードをもとに、全体に占めるサービス別コスト割合をグラフ化したものです。グラフから明らかなように、Amazon S3(Amazon Simple Storage Service)が AWS コストの半分 近くを占めています。

S3 のコストカットが急務という訳です。

 

S3コスト対象

実際に S3 のコストを分析する前に、S3 を利用するうえでかかるコスト対象を一部抜粋して整理します。(Amazon S3 の料金 より2022年12月23日現在)

要素 分類 コスト
ストレージ S3 標準 最初の 50 TB/月:0.025USD/GB
次の 450 TB/月:0.024USD/GB
500 TB/月以上:0.023USD/GB
S3 標準 – 低頻度アクセス すべてのストレージ/月:0.0138USD/GB
S3 Glacier Instant Retrieval すべてのストレージ/月:0.005USD/GB
S3 Glacier Deep Archive すべてのストレージ/月:0.002USD/GB
リクエストと
データ取り出し
PUT、COPY、POST、LIST リクエスト
(1,000 リクエストあたり)
S3 標準:0.0047USD
S3 標準 – 低頻度アクセス:0.01USD
S3 Glacier Instant Retrieval:0.02USD
S3 Glacier Deep Archive:0.065USD
GET、SELECT、他のすべてのリクエスト
(1,000 リクエストあたり)
S3 標準:0.00037USD
S3 標準 – 低頻度アクセス:0.001USD
S3 Glacier Instant Retrieval:0.01USD
S3 Glacier Deep Archive:0.00037USD
ライフサイクル移行リクエスト (入)
(1,000 件のリクエストあたり)
S3 標準 – 低頻度アクセス:0.01USD
S3 Glacier Instant Retrieval:0.02USD
S3 Glacier Deep Archive:0.065USD
管理と分析 S3 Analytics – Storage Class Analysis モニタリングされるオブジェクト 100 万個あたり/月:
0.10USD
S3 Storage Lens の
高度なメトリクスと推奨事項
モニタリングされる 100 万個のオブジェクトあたり:
0.20USD/月

ストレージクラスの変更で純粋なストレージコストは抑えられますが、GET や PUT 操作によるコストが割り増しとなるコストモデルとなっています。また、S3 ストレージ管理機能と分析はオブジェクトサイズに依らず、対象のオブジェクト数でコストが変動することに留意が必要そうです。

 

S3コスト分析

では、実際にどの要素・分類に S3 コストは多くかかっているのでしょうか?ある月の請求書からその内訳を見ていきます。

S3コスト 内訳

Amazon S3 の AWS 請求および使用状況レポートを理解する によれば

  • TimedStorage-ByteHrs:S3 Standard ストレージに保存されたデータの GB-時間の数
  • Requests-Tier1:STANDARD、RRS およびタグに対する PUT、COPY、または POST リクエストに加え、すべてのバケットとオブジェクトに対する LIST リクエストの数
  • Requests-Tier2:GET および他のすべての non-Tier1 リクエストの数

という整理になります。S3 Standard(標準)のストレージが S3 コストの約 95 %を占める ことになります。

したがって、今回の S3 コストカットの要点は 2 つです。

  1. ストレージ容量の削減
  2. ストレージクラスの見直し

 

1. ストレージ容量の削減

不要なオブジェクトの削除とライフサイクル設定でストレージを絞っていきます。

調査

とは言え、本番稼働しているシステムのデータを闇雲に削除するのは無論危険です。地味な作業ではありますが、いくつか調査をする必要があるでしょう。

① 要件の確認

システムにおいてセキュリティやコンプライアンスによるデータ保持期間に要件が設けられていれば、その要件に従います。
例えば、非機能要件で 1 年分のデータを保持しておくと決まっているシステムであれば、自ずとライフサイクルの設定も 1 年で削除となりますね。

② 実装の確認

過去遡ってオブジェクトを参照しているか、参照しているのであればどの程度以前のオブジェクトを参照しているか、を実装レベルで確認します。
今回ターゲットのシステムには、広告入稿で非承認となった過去 1 週間分のデータをレポートとして出力するシステムがあります。このシステムの場合には少なくとも 1 週間分はオブジェクトを残しておく必要がありますね。

③ 効果の確認

ストレージ容量の削減によって得られるコストカット期待効果を確認します。
効果は定量的に計測はできるので、④ 運用の確認 でオブジェクトを残しておく期間をつめる際のものさしになります。また消極的には、削減に要す人的コストを上回るコストカットができるか、その費用対効果を確認する目的もあります。

効果は、\(削減対象の合計サイズ \times S3 標準のストレージコスト\) で概算しました。

  • 不要なオブジェクトの合計サイズの確認

AWS マネジメントコンソールからバケットやオブジェクトプレフィックス、オブジェクト単位でサイズを確認することができます。Amazon CloudWatch によるメトリクスのモニタリングダッシュボードで S3 Storage Lens のメトリクスを表示する合計サイズを計算するアクションを利用するのが楽ですね。

S3 合計サイズを計算する

  • ライフサイクル設定による削減対象の合計サイズの確認

ライフサイクルの設定に応じて確認する必要があります。代表的な オブジェクトの有効期限 によるライフサイクルを設定する場合には、有効期限が切れる以前のオブジェクトの合計サイズから見積もります。

aws s3api list-objects --bucket 【削除対象バケット】 --prefix 【削除対象オブジェクトプレフィックス】 --query 'sum(Contents[?LastModified < `【有効期限が切れる日】`][].Size)'

例として、dummy バケットの dummy プレフィックスから始まるオブジェクトに 1 年の有効期限でライフサイクルを設定する場合の効果を概算してみます。

aws s3api list-objects --bucket 'dummy' --prefix 'dummy/' --query 'sum(Contents[?LastModified < `2021-12-23`][].Size)'
34909060913447
aws s3api list-objects --bucket 'dummy' --prefix 'dummy/' --query 'sum(Contents[?LastModified >= `2021-12-23` && LastModified < `2021-12-24`][].Size)'
191066459851

ライフサイクル初回実行時は、有効期限切れのオブジェクトが一挙に削除されます。したがって、ここでは最終更新日時が 1 年より前のオブジェクト合計サイズと最終更新日が 1 年前のオブジェクト合計サイズを導出しています。
\(34909GB \times 0.023USD/GB = 803USD\) よりライフサイクル初回実行時の瞬間効果は約 11 万円/月、\(191GB \times 0.023USD/GB \times 30日 = 132USD\) よりライフサイクル設定後の継続効果は約 2 万円/月となります。

なお、合計サイズを計算するアクションや AWS CLI による SELECT 操作も微々たるものですがコスト対象となります。できるだけデフォルトで用意されているメトリクスから確認すること、リクエスト数を抑えることをおすすめします。

④ 運用の確認

最後に運用観点で確認します。運用上 1 週間、1 か月、1 年という単位で過去に遡ってオブジェクトを参照するケースが少なからずあると思います。システムでは参照していなくても、手動オペレーションで過去のオブジェクトを参照する場合にはその期間だけオブジェクトを残しておく必要があります。
オペレーションテクノロジーは、私が属す開発部隊と運用部隊が分かれています。したがって、削減対象のシステムごとに運用担当の方とオブジェクトを残しておく期間、いつ実際に削除するのかをつめました。

実施

不要なオブジェクトを削除し、ライフサイクルを設定します。

① 事前検証

オブジェクトが削除されてシステムに本当に問題がないかを事前に検証しました。具体的には削除対象のバケット、オブジェクトプレフィックス、オブジェクト単位で手動リネームし、システムに問題が発生しないこと、運用目線で不都合がないことを 2 週間に渡って静観しました。
基本的には mv でリネームします。

aws s3 mv --recursive s3://【削除対象バケット】/【削除対象オブジェクトプレフィックス】/ s3://【削除対象バケット】/【リネームした削除対象オブジェクトプレフィックス】/

ただし、mv ではバケット単位のリネームはできないので、移し替えるような操作が必要になります。

aws s3 sync s3://【削除対象バケット】 s3://【リネームした削除対象バケット】
aws s3 rb --force s3://【削除対象バケット】

rb --force は、オブジェクトを含めバケットごと強制削除となるので慎重に実施してください。

② 不要なオブジェクトの削除

さて、実際にオブジェクトを削除していきます。削除方法はとてもシンプルですね。

aws s3 rm --recursive s3://【削除対象バケット】/【リネームした削除対象オブジェクトプレフィックス】/

バージョニングが有効な場合には、面倒ですが旧バージョンを含め削除が必要です。

aws s3api delete-object --bucket 【削除対象バケット】 --key 【削除対象オブジェクトプレフィックス】/【削除対象オブジェクト】 --version-id 【削除バージョンID】
aws s3 rb s3://【削除対象バケット】

③ ライフサイクルの設定

ライフサイクルは、バケットのライフサイクル設定の指定S3 コンソールの使用のように AWS マネジメントコンソールから設定するのが楽です。
先と同じように dummy バケットの dummy プレフィックスから始まるオブジェクトを有効期限 1 年のライフサイクルとする場合は、このような設定になります。

S3 ライフサイクルルールを作成する

バージョニングが有効な場合には、オブジェクトの非現行バージョンを完全に削除と合わせて設定することになります。

観察

ストレージ容量が削減できていること、システムに問題が発生していないことを観察します。
ストレージ容量は Amazon CloudWatch によるメトリクスのモニタリングダッシュボードで S3 Storage Lens のメトリクスを表示する から確認が可能です。なお、ライフサイクルは設定後の翌9:00(JST)に初回実行 となるのでご注意ください。

S3 バケットメトリクス

上はあるバケットに対し、2 度に分けてライフサイクルを設定した実際のメトリクスです。ストレージ容量にして 100 TB、単純計算で 31 万円/月あまりの削減 となっています。
加えて、オブジェクト数も 100 万個あまり減っています。S3 コスト対象を思い出すと、管理と分析は対象のオブジェクト数でコストが変動するので、副次的に管理と分析コストも削減 できたことになります。

改善

ストレージ容量の過剰な増加を再発防止するため、継続的な観察と改善をしていくことが望ましいですね。
システムの要件にもよりますが、ストレージ容量は一定となることが理想です。もしそうでないのであれば、改善の余地があるかもしれません。
もしストレージ容量が増加傾向にある場合には

  • 追加でライフサイクルを設定
  • ファイル圧縮処理の追加もしくは見直し

を再考するとよさそうです。

 

2. ストレージクラスの見直し

なんらかの理由で削除できないオブジェクトを、適したストレージクラスへ移行します。

アクセスパターンが予測不可能または変化する場合

Amazon S3 Intelligent-Tiering を利用するのがよさそうです。
念のため説明をすると、Amazon S3 Intelligent-Tiering はオブジェクトに対するアクセスパターンをモニタリングし、あまりアクセスされていないオブジェクトをより低コストのアクセス階層へ自動的に移動させるストレージクラス になります。
これだけ聞くと設定して損がないように思えますが、Amazon S3 Intelligent-Tiering にはストレージコストとは別にモニタリングコストとしてオブジェクト 1,000 件あたり 0.0025USD かかります。極端にストレージ容量が小さくオブジェクト数が多いような場合には、むしろコストが割り増しとなる 可能性があることに注意が必要です。また、ストレージクラスは基本的にはオブジェクトを PUT する際に指定する必要があるため、実装を変更しなければいけない 場合があります。
実装の変更が必要になること、アクセスパターンが概ね予測可能で変化しないことを鑑み、今回は採用を見送りました。

アクセスパターンが予測可能で変化しない場合

アクセス頻度に応じてストレージクラスを設定します。

  • 既存オブジェクトのストレージクラス変更

AWS マネジメントコンソールのストレージクラスを編集するアクションで変更するのが楽です。

S3 ストレージクラスを編集する

S3 ストレージクラスを編集する

  • ライフサイクルでストレージクラスを移行

ライフサイクルルールを作成する中でオブジェクトの最新バージョンをストレージクラス間で移動もしくはオブジェクトの非現行バージョンをストレージクラス間で移動を利用します。

ただし、Amazon S3 ライフサイクルを使用したオブジェクトの移行 にある通り、いくつか制約はあるので注意が必要です。また、ライフサイクル移行リクエストに対してもコストがかかります。特にライフサイクル初回実行時は大量のストレージクラス移行が発生し、相応のコストがかかることは認識しておく必要があります。

今回ターゲットのシステムには、過去 90 日あまりの日次フィードデータを運用部隊が参照できる管理システムがあります。日次フィードデータは日数の経過とともに参照頻度が指数関数的に減る一方、1 週間前、1 か月前という単位で参照することがあり、万が一のために 1 年程度は残しておきたいという要件がありました。
この対象に対しては、1 か月で S3 標準 – 低頻度アクセス、90 日で S3 Glacier Instant Retrieval に移行、1 年で削除するというライフサイクルを設定しました。

S3 ライフサイクルでストレージクラスを移行する

日数の指定に悩んだり、裏付けが必要な場合には Amazon S3 分析 – ストレージクラス分析 が有用です。
ストレージクラス分析では、S3 にアップロードされてからの経過時間に応じた保存されたバイト数や取得率などを確認することができます。

ストレージクラス分析の平均アクセスメトリクス

着目すべきは取得レートの青いグラフです。グラフから、直近 15 日間にアップロードされたファイルは多く参照され、それよりも前にアップロードされたファイルはほとんど参照されていないことが分かります。このように取得されていないことが明確に分かれば、安心してライフサイクルによるストレージタイプ移行が設定できますね。

 

まとめ

本番稼働しているシステムのストレージ容量を削減し、ストレージクラスを見直すのは骨の折れる作業でした。ジョインして間もないことも加味すると、特に 実装の確認 には苦労しました。

しかし、コストカットは定量的な結果として出てくるため、削減できたときの喜びは大きかったですね。結果として今回は、瞬間効果にして 168529GB より約 53 万円/月と、継続効果にして 23833GB より約 7 万/月、年間にして約 1,200 万円ものコストカットができました。

まだまだ AWS コスト全体の見直しをしている最中なので、その全容はまた別の記事で書ければと思います。

とても泥臭く、ある意味で生々しい内容でしたが、皆さんが S3 コストカットを実施する際の道標になればなによりです。それではよいクリスマスを!