S3のコストダウンを実施してみた

※本ブログは2022/2に執筆されています。そのため、アップデートによって内容が現在と異なる可能性があります。

はじめに

モバイル事業本部プロダクトエンジニアリングセクション マネージャーの安田です。 インフラっぽいことやクラウドっぽいことやデータエンジニアっぽいことをやってます。 今回、モバイル事業部で使うS3のコスト削減のため、ストレージクラスの移行等を行うライフサイクルの設定を行いましたのでご紹介します。 これからS3の管理を行っていく方、コスト削減に興味のある方の参考になれば幸いです。

実施の背景

モバイル事業本部ではドワンゴジェイピーやアニメロミックスなど音楽配信ビジネスを中心に展開しており、様々なレーベルからお預かりした楽曲データを管理しています。 また、ニコニコ事業本部ができる前からサービスを行っており、多大な量のシステムログやクラウドサービスのログデータなどが存在しています。 それらの多くはAmazon Simple Storage Service (Amazon S3)に保存されており、複数のバケットに分かれて保存されています。 これまではそれらをすべて「S3標準」(以下Standard)のストレージクラスに保存していました。

以前からストレージクラスを変更することでコストダウンが可能なことは知っていたのですが、ずっと実施して来ませんでした。 ストレージクラスの機能に柔軟性が足りなかったことや、サービスの展開によりデータの使用傾向が大きく変化していた時期だったからです。 しかし、2018年にはIntelligent-Tieringという柔軟なストレージクラスが発表され、2021年9月に機能もアップデートされたことや、モバイル事業のデータ利用傾向もある程度安定してきたことから、ストレージクラスの移行実施を検討しました。

本ブログでは実施に際して、何を考慮しなければいけないか、注意点や躓きポイント、実施した結果などをご紹介していきます。

ストレージクラスとは?

一般的に、データによって重要度やアクセスの必要性、アクセス頻度が違うと思います。 例えば、WEBページのようなデータであればアクセス頻度は高いでしょうし、ログのようなデータであれば古いものは年に数回程度のアクセス頻度でしょう。 S3ではそのような要件に応じてコストを最適化できるように、ストレージクラスという仕組みを用意してくれています。

Standardに対して他のストレージクラスは数分の1の価格でデータを保存することができます。 ただし、データにアクセスをする際には取り出しデータ量に応じて料金がかかったり、アクセス可能になるまでに時間がかかったりといった違いがあります。

今回の施策では以下の4つのストレージクラスを使用しました。 それぞれの比較において重要な項目のみ書いておきます。 詳細は公式のコストページをご覧ください。 カタログスペック的な話なので、ご存じの方はスルーしていただいて結構です。

1. Amazon S3標準–低頻度アクセス (以下、SIA)

  • メリット
    • Standardとほぼ同じ要件で利用可能
    • ストレージ料金はStandardの大体55%程度
  • デメリット
    • 最低サイズが128 KB
    • 最小ストレージ期間が30日(30日以内に削除されると残り日数分の料金が加算される)
    • APIコール料金はStandardの2倍~3倍
    • データアクセス量に対して0.01USD/GB
    • ライフサイクル移行リクエスト料金が1,000オブジェクトあたり0.01USD

2. Amazon S3 Glacier Instant Retrieval (以下、GIR)

  • メリット
    • Standardとほぼ同じ要件で利用可能
    • ストレージ料金はStandardの大体20%程度
  • デメリット
    • 最低サイズが128 KB
    • 最小ストレージ期間が90日(90日以内に削除されると残り日数分の料金が加算される)
    • APIコール料金はStandardの3倍~4倍
    • データアクセス量に対して0.03USD/GB
    • ライフサイクル移行リクエスト料金が1,000オブジェクトあたり0.02USD

3. Amazon S3 Glacier Deep Archive (以下、GDA)

  • メリット
    • ストレージ料金はStandardの大体8%程度
  • デメリット
    • Standardと同じ要件で利用できない(即時アクセスできない)
    • 最低サイズが128 KB
    • 最小ストレージ期間が180日(180日以内に削除されると残り日数分の料金が加算される)
    • 一部APIコール料金はStandardの14倍程度
    • データアクセス量に対して0.022USD/GB
    • ライフサイクル移行リクエスト料金が1,000オブジェクトあたり0.065USD

4. Amazon S3 Intelligent-Tiering (以下、INT) ※ディープアーカイブオプションは不使用

  • メリット
    • Standardとほぼ同じ要件で利用可能
    • アクセス傾向を判断し、自動的にStandard/SIA/GIR相当のストレージクラスに移行してくれる
    • ストレージ料金はアクセス傾向によってStandard/SIA/GIR並みとなる
    • 取り出し料金が発生しない
    • ストレージクラス移行料金が発生しない
    • APIコール料金はStandardと同じ
  • デメリット
    • 監視・オートメーションコストとして常にオブジェクト1,000 件あたり 0.0025USDかかる
    • 最低サイズが128 KB ⇒ 2021/9のアップデートで128KB以下の監視・オートメーションの料金が無料に!
    • 最小ストレージ期間が30日 ⇒ 2021/9のアップデートで0日に!
    • 移行後、30日・90日監視されないとコストメリットが出ない
    • ライフサイクル移行リクエスト料金が1,000オブジェクトあたり0.01USD

いかがでしょうか? 思った以上に複雑な項目で課金されるな、と思われたのではないかと思います。 また、単純に安いストレージを選択すればよいわけではないということはわかっていただけたかと思います。 最初の印象では、INTが非常に優秀で使いたいと思う一方で、オートメーション費用としてオブジェクトに継続的に課金されてしまう点が気になりました。

私的なそれぞれのストレージクラスの用途については、ざっくりいうと以下のようなものだと考えています。

  • SIAはアクセスはあまりされないが、長期保存しておく必要があるもの
  • GIRはアクセスはされない前提のオブジェクトで、長期保存しておく必要があるもの
  • GDAは塩漬けにするデータ・アクセスしたいときには翌日以降にアクセスできれば良いもの
  • INTはアクセス傾向が読めず、古いファイルにも一定量以上アクセスがあるもの

何を重要視したか

今回、ストレージクラスを選択する際に重要視した点をまとめます。

コードに変更を加えずに利用できること

S3をコンソールやCyberduck等から手動で更新することもあるかと思いますが、多くはコーディングされた一連の処理の中でデータの取得や出力がなされます。 今回選択したGDA以外のストレージクラスはプログラムの変更なしに利用することができます。 より安いアーカイブ層のストレージクラスを多く使おうとする場合、利用するソフトウェアに一工夫必要になり改修コストがかかってしまいますので、使用を避けました。 GDAはコードからも一切アクセスされないオブジェクト・バケットに対して使用しました。

コストが低くなること

当たり前のことを言っているのですが、結構大事な観点です。 Standardから他のストレージクラスに移行すると基本的にはストレージ料金は下がります。 ですが、アクセスの頻度やアクセスデータ量が多いバケットだと結果コストが高くなる可能性もあります。 容量の小さいバケットはコストダウンを目的にした場合、対応をする必要性が低いということでもあります。 また、不要なファイルは削除するのが一番いいのです。 どのストレージクラスを利用するか、という前に「定期削除してはだめなのか、平均ファイルサイズは移行効果があるサイズなのか、無駄なバージョニングはされていないか」などを調査しました。

移行コストがどのくらいかかるか

ストレージクラスの移行にはストレージ移行コストがかかります。 ストレージクラスによって異なる費用ですが、オブジェクト数が多くなると結構バカにならない費用が加算されます。 オブジェクト数が1億を超えてくるようなバケットだと1回ライフサイクル移行するのに1000USDほどかかってきますので、結構大きいですよね。 また、その移行費用は移行実施日にかかります。 ですので、実施前にいくらかかるのかを割り出し、その費用が急に請求に載ってもびっくりしないでね、と関係各所に連絡と調整をしました。

移行の準備をする

対象となるバケットを決める

ストレージクラス移行はコストダウンが目標でした。 ですので、まずはコストメリットの大きいバケットに絞って実施をしました。これはバケットを容量順に並べてみて、上位〇個や〇TB以上あるバケット、などそれぞれ基準を設けるとよいと思います。 CloudWatchで1日1回取得されていますので、S3のメトリクスから「BucketSizeBytes」を確認すると把握できると思います。 または、S3の左ペインにあるStorage Lensのダッシュボードを見ると、バケット単位のストレージ合計・オブジェクト数・平均オブジェクトサイズが取得できますのでおススメです。

今回の施策では上位10個ほどを移行対象にしました。

現状の使われ方を把握する

次に実施したことは、現在のS3のバケットの使われ方を把握することです。 それにはストレージクラス分析の機能を利用しました。 ストレージクラス分析を利用することで、ストレージクラス毎に使われ方やアクセス傾向を把握することができます。 以下のような情報を得ることができました。

current-usage-graph
current-usage-graph2
current-usage-graph3

バケット毎に設定する必要があるため、マネージメントコンソールからS3の対象バケットを表示し、上部ペインの「メトリクス」⇒ストレージクラス分析の項目にある「分析項目を作成」から作成できます。 ストレージクラス分析を作成して数日すると、ある程度の傾向が把握できるようになりますが、より正確に傾向を測るためには1ヶ月程度分析し続けることが望ましいです(モニタリングされるオブジェクト 100 万個あたり/月 0.10USDかかります)。

現状の使われ方を把握する(2)

現状の使われ方を把握する上で、利用者へのヒアリングは非常に重要です。 ヒアリングをすることで、古いデータを消してもよいのか・消してはいけないのか、古いデータにアクセスをする業務があるのかなどを把握しました。年1実施する処理のようなストレージ分析では見えない範囲の業務を把握することができます。

バケット毎の移行方針を立てる

ストレージクラス分析やヒアリングから取得した情報はまとめると以下になります。

  1. ストレージクラス別の保存傾向
    • オブジェクト作成後の経過日数毎の保存バイト数がわかる
      • 保存されたファイルが多いボリュームゾーンを知ることで、何日目からファイルをストレージクラス移行するとコストメリットが大きいかを知ることができます。
  2. 取得レート
    • どの程度古いデータにアクセスされているかがわかる
      • 取得レートが高いデータをストレージ移行してしまった場合、そこにアクセスが多くされてしまい、ストレージのコストダウンの効果よりアクセス費用が掛かってしまうこともあり得ます。
      • 作成後365日以上前のデータにもアクセスが多い場合などは、ファイルの生存期間に依存しないアクセス傾向にあるバケットであると判断できます。
  3. ヒアリング
    • データの削除の可否や突発的な業務の有無を確認する

入手した情報を元に、バケット毎に検討をした結果、今回のケースでは大まかに4パターンのバケットの傾向に分類できました。

  1. アクセス傾向がファイルの生存期間に依存しない全体にアクティブなデータが多いバケット
    • INTを選択
  2. 作成直後のデータには頻繁にアクセスされるが、その後のデータにはほぼアクセスされないバケット
    • 30日程度でSIAに移行⇒その後一定日数経過後にGIRに移行
  3. 作成直後のデータには頻繁にアクセスされるが、その後のデータは不要になるバケット
    • ストレージ移行をせず、一定経過後に削除
    • テスト環境・開発環境のバケットなど
  4. 保存しておく必要はあるが、誰からも一切アクセスされないバケット
    • GDAを選択

コストを試算してみる

コストの試算ではバケット毎に現状の費用・ストレージクラス移行費用・移行後月額費用を算出しました。ライフサイクルでの移行の場合、オブジェクトサイズが128KB以下のものは対象外なのですが、その数を特定する方法が簡単にはなかったため、すべてのオブジェクトをストレージクラス移行するものとしてMaxの移行費用を計算をしました。実際の移行費用は試算より小さくなるはずですし、128KB以下のものは移行対象外となってもサイズが小さいため、せいぜい数%の差にしかならないので、試算としてはこれで十分な精度です。 計算上、最終的には対象バケットのコストは約70%程度コスト削減でき、移行コストは半月でペイできるという試算になりました。(実際は想定外のアクセス費用やAPIコールの費用などがかかるため、ここまで想定通りはいかないとはおもいますが。。。)

ただ、ここでいくつかの問題が見つかりました。

バージョニングデータの計画が漏れていた

いくつかのバケットではバージョニングが有効になっていました。バージョニングされたデータにも現行のオブジェクトと同様にストレージクラスが指定されています。こちらは追加でバージョニングの削除とも合わせてストレージクラスの移行を計画しました。

オブジェクト数が多すぎる

いくつかのバケットはオブジェクト数が多すぎるため、ストレージクラス移行費用がストレージコスト削減料金を大きく上回ることがわかりました。特に、ELBやCloudfrontのアクセスログを保存するバケットはアクセス単位でログが保存されていて、非常に小さい平均オブジェクトサイズとなっていました。そのようなバケットは別の方法でオブジェクトを何かしらの単位で一つにまとめることでオブジェクト数を減らして対応することが効果的です。ですので、今回のライフサイクル+ストレージクラスによる対応から対象外としました。

ライフサイクルを設定する

設定日

今回は継続的にストレージ移行を実施したいため、ライフサイクルを設定することによるストレージクラスの移行を設定しました。まずはパターンの異なる2つのバケットを選んで、コンソールから設定をしてみました。

サンプルで一つの設定例を載せておきます。 設定内容はバケットの全オブジェクトを対象にして、30日後のオブジェクトをSIAに移行する。150日後のオブジェクトをGIRに移行する、という内容です。

life-cycle-settings

よし。作成完了。 ライフサイクルの実行タイミングは0時0分(UTC)ですので、翌日を楽しみにしていました。

翌日

意気揚々とS3のコンソールを開いて確認してみた私

が・・・・駄目っ・・・・・! たった一つのオブジェクトもストレージクラス移行されていませんでした・・・

ということで、調査開始。 こちらがライフサイクル設定をAPIから取得した内容になります。

$ aws s3api get-bucket-lifecycle-configuration --bucket sample-bucket

{
    "Rules": [
        {
            "ID": "lifecycle",
            "Filter": {},
            "Status": "Enabled",
            "Transitions": [
                {
                    "Days": 30,
                    "StorageClass": "STANDARD_IA"
                },
                {
                    "Days": 150,
                    "StorageClass": "GLACIER_IR"
                }
            ]
        }
    ]
}

ソリューションアーキテクトの方とも相談しながら調査を進めたところ、どうやらCLIから設定した場合には正常に動作するライフサイクルが設定できるということがわかりました。正常に動くライフサイクルの設定をAPIで取得した結果がこちらです。

{
    "Rules": [
        {
            "ID": "lifecycle",
            "Filter": {
                "Prefix": ""
            },
            "Status": "Enabled",
            "Transitions": [
                {
                    "Days": 30,
                    "StorageClass": "STANDARD_IA"
                },
                {
                    "Days": 150,
                    "StorageClass": "GLACIER_IR"
                }
            ]
        }
    ]
}

なんと、コンソールから行ったライフサイクルの設定にはPrefixが入ってないのです どうやらAPIのversionがv2になったときのバグ?があるようで、コンソールから設定をしても正常に動作しないようです。 (2022-02-17 追記:こちら、現在はコンソールから設定しても問題なく動作するようです。 また、get/put-bucket-lifecycle-configuration で設定した際のprefixの追記は必要なく、getしたものと同じjsonで設定できました。)

そこで、Prefixを自分で追加設定して、今度は設定をAPIからputすることにしました。そのために、上記ライフサイクルの設定をjsonファイルに記載します。そしてAPIから以下のコマンドを実行しました。

$ aws s3api put-bucket-lifecycle-configuration  \
  --bucket sample-bucket  \
  --lifecycle-configuration file://sample-bucket.json

何もエラーはなく、成功したようです。コンソールから見ても何も変化はありませんでしたが、再度APIからGETするときっちりPrefixが設定されていました。

また翌日

恐る恐るコンソールを確認すると・・・

無事動作していました!! 対象バケットのメトリクスはこのようになりました(画像は数日後のもの)

bucket-size-metrics

Standardが大幅に減り、移行されたSIAとGIRのデータ量が表示されるようになりました! 最後に、各ストレージクラスの容量が、事前に計算していた容量と大きな差がないことを確認し、他のバケットにも設定を行いました。

ライフサイクル設定後にチェックすること

総コスト

ライフサイクルに設定した後、想定通りコストがダウンしているか、想定外のコスト増が発生していないか等を確認する必要があります。また、気を付けなくてはいけないこともいくつかあります。Cost Explolerで確認をすると最小単位で1日毎にコスト管理が可能です。

  • 2日程度経たないとCost Explolerに値が記載されない項目があります
    • 気長に待ちましょう
  • INTは30日経過しないと低アクセスレイヤに移行されないので、INTに移行したバケットのコストは設定後すぐには削減されません
    • 即コストダウンすると思っていると想定より効果が少ないと感じてしまうかもしれません
  • 最低利用期間前に別のストレージクラスに移行されたオブジェクトや削除されたオブジェクトがある場合、APN1-EarlyDelete-SIAやAPN1-EarlyDelete-GIRの費用として請求されます。それらの項目が大きすぎる場合、想定していなかった利用ケースがある可能性もありますので注意が必要です。
    • 今回の例ように、ライフサイクルによって30日でSIA、150日でGIRに移行するライフサイクルを設定した場合、多少EarlyDeleteが発生してしまいます。例えば、作成後149日経過したオブジェクトは初期設定でSIAに移行されますが、翌日は150日なのでたった1日でGIRに移行することとなってしまい、残りの29日分のストレージ費用がEarlyDelete-SIAとして請求されます。
    • 実際、APN1-EarlyDelete-SIAが計上されていました。本施策のケースでは1日数USDですがかかっており、ほかのバケットで同様の設定をした場合にも最初の30日は想定よりも多少コストが増えてしまうと思います。(GIRの移行を30日間遅らせるという方法もありますが、そちらの方がオペレーションコストやGIRによるコスト削減が遅れることでのコスト増になるケースが多いと思います)

アクセス傾向

今回は事前にストレージクラス分析やヒアリングを行い、利用者の利用傾向を可能な限り把握してから設定を行いました。ただ、サービスの増減やデータ分析の導入など様々なケースでアクセス傾向が変わってくることが想定されます。 少なくとも月1回程度はS3のアクセス料金やオブジェクト数の推移などを確認して、想定外のアクセスがされていないかをチェックしていく必要があるのかなと思っています。

最後に

今回はライフサイクルによるストレージクラスの変更を実施しました。具体的な設定というよりは移行計画を立てる方法や注意点についてフォーカスした説明をさせていただきました。 移行のコスト削減効果は実施直後の現在でも多少出てきており、90日後にINTが自動的にアーカイブ層に移行されるのが待ち遠しい限りです。

最初はストレージクラスの種類の多さや課金されるアクションや項目の多さなどで全容把握に非常に苦労しましたが、一つずつクリアにしていき、当初狙っていたコストダウンの効果をほぼほぼ得ることができました。

実施してみてINTは非常に優秀だなと感じました。最初気になったINTの管理・オートメーション費用ですが、オブジェクトが1億を超えてくるようなバケットでは多少気にはなりますが、それでもストレージ移行の自動化はメリットが大きいのかなと思います。

あとは、改めてデータレイク設計を利用当初からもっときめ細かくやっておけばよかったなと思いました。バケット単位でデータの種類や生存期間などを可能な限り統一することで、より適したストレージクラスの選択も可能になりますので、今後の設計に生かしていきたいと思いました。

この記事を見た方が「自分のS3でもやってみよう」と思っていただけたら幸いです。

株式会社ドワンゴでは、教育事業、ニコニコ事業、モバイル事業など様々なサービス、コンテンツを一緒につくるメンバーを募集しています。ドワンゴに興味がある。または迷っている方がいれば、気軽に応募してみてください。