広告技術部のUTです。 最近はカービィディスカバリーをゆっくりやってます
概要
昨今ではデータドリブンな意思決定を重視する企業がどんどん増えており、データを活用することにより事業成長へのインパクトを出そうとしています。 データを事業へと活用するためには、蓄積されるデータを分析するために保管しておく必要があります。
弊社も創業時からデータを蓄積し事業に活用することに力を入れてきた企業の一つであり、日々大量のログが収集されています。 またAWSアカウントを複数運用していますが、一番データ量の多い広告アカウントのS3にはペタバイトレベルのデータが保管されています。
普段何気なく使っているデータレイクとしてのS3ですが、少量であれば無視できるくらい小さいので、コストを気にせず使っておられる方も多いのではないでしょうか? そのようなS3でも巨大な容量を標準のストレージクラスに保存していると、実は大きなコストが発生しています。
では1PBで標準のストレージクラスに保存している場合の試算をしてみましょう。 S3の料金は以下ページを参考に、月額の費用を計算します。
0.025USD/GB * 50,000GB + 0.024USD/GB * 450,000GB + 0.023USD/GB *500,000GB = 23,300USD/monthとなります。 今は円安で124円なのでなんと 2,889,200円/月になります。
こういった分析用のログは削除できれば削除するのが一番良いのですが、監査やバックアップといった用途のため数年間残しておく必要があり、 それらのログはほぼ使わないにも関わらず、削除することはできません。 そのため、時間が経てば経つほどログの量が増え、ストレージのコストがかさみます。 こういった、S3に日々蓄積されるログの保存コストをどうやって抑えるかという問題は、社内で長らく重要な課題の一つになっていました。
過去の失敗
対策としてまず思いつくのがS3のライフサイクル設定によってGlacier などのコストの安いストレージへ移管する方法です。 しかし、この対策は過去に失敗して実行できませんでした。
Glacier のストレージ料金は通常のストレージに比べて安いのですが、GlacierストレージへのPUTによる料金は通常のストレージより大幅に高く設定されています。 2022年4月現在、通常のS3のコストが1000リクエストあたり0.0047USDなのに対し、Glacier (flexible) は1000リクエストあたり0.03426USDとなり約7.3倍です。
弊社のS3に保管しているログは各APIの複数ノードから送られてくるためファイルは細切れになっており、 オブジェクトサイズは小さいのですがオブジェクト数は多いという状態です。 このような性質のオブジェクト群に対してライフサイクルを設定してしまったが故に、 Glacierストレージへ大量のリクエストが発生し、数万ドルの請求が発生するという事件になりました。
どうやったか
上述の件もありS3のコスト削減の件はしばらく保留されていたのですが、大きなコスト削減ポイントでもあったので、再度挑戦することになりました。
今回検討した方法は、MultipartUploadを利用して複数のgzipファイルを単一のgzipファイルにまとめるという方法です。 単一のファイルを一つにまとめることができれば、GlacierへのPUTリクエストの回数を大きく削減することができます。
gzipファイルは複数ファイルを結合しても読み込むことができます。 RFC 1952 - GZIP file format specification version 4.3 には 以下のように記載されています。
A gzip file consists of a series of "members" (compressed datasets). The format of each member is specified in the following section. The members simply appear one after another in the file, with no additional information before, between, or after them
実際にgzipファイルに対してcatしてみるとgzcatで読めることがわかります。
cat a.csv.gz b.csv.gz > c.csv.gz gzcat c.csv.gz
そのためmultipartによって単一ファイルにまとめ上げても変わらずにgzipファイルとして扱うことができます。
仕組み
標準のストレージクラスの複数のgzipファイルをまとめて単一のgzipファイルにしそれを別のストレージクラスに格納する CLIを作成し、それをdigdagで定期的に実行しています。 今回のアーカイブ対象のログは普段ほぼ利用しませんが監査対応などで保管しておく必要があるので、ストレージ料金の一番安いGlacier Deep Archiveへ格納します。
CLIが実行する具体的な流れとしては、
- 指定したディレクトリのS3のgzipファイルのリストを取得
- それぞれをダウンロードし、ローカルのbufferファイルに詰めていく。
- ローカルのbufferが5MBを超えたらS3に対して標準のストレージクラスのmultipart uploadを実行
- S3のmultipart uploadの合計が5GBになったらそのmultipart を完了させ、新しいmultipart ファイルを作成する。
- 完了したmultipartファイルをS3 object copyを使ってストレージクラスを変換する
- ストレージクラスの変換が完了したら、アーカイブ実施前のgzipファイルを削除する
となります。
multipart uploadも1リクエストとみなされるので、まずmultipart uploadを標準のストレージクラスに対して行い、容量制限の5GBまで溜まったらGlacierにCOPYすることでGlacierへのリクエストを最後のコピーの1回だけに抑えることができます。
結果
大きな割合を占めていたログのアーカイブを過去分も含め実施することでS3のコストを三分の一ほど削減することができました。 S3のコストは固定費となってしまうので、この削減によって継続的にコストが減らせるのは大きな改善でした。 仕組みとしてもCLIとそれを呼び出すdigdagの設定のみということで転用もしやすく、他のアカウントなどでも削減が期待できます。
まとめ
今回の記事では、社内で取り組んだS3のコスト削減方法を取り上げました。
サービスを運営する上でインフラコストは常に意識しておくべきポイントであり、引き続き削減対象を検討しています。