HDE BLOG

コードもサーバも、雲の上

S3のZipファイルをRangeでバイナリアクセスして料金を節約

あけおめころよろメリクリ!!
尾藤 a.k.a. BTOです。

今年も残すところ、あと357日となりましたが、みなさんいかがおすごしでしょうか。

今年の目標は、純白のメルセデス、プール付きのマンション、最高の女とベッドでドン・ペリニヨンの3つです。

さて、今回はS3上に置いたZipファイルをHTTPのRangeパラメータでバイナリアクセスして、料金を節約した話を書きます。

検索インデックスのデータ量が増大

メールアーカイバでは、検索インデックスを mongodb に格納していますが、データ量が増えるにしたがって性能的な問題が出てきました。なにしろ月間1億6000万通のメールを処理するので、検索インデックスのデータ量も大変なことになります。

amazon EBS 1TB制限

当時のEBSでは、最大で1TBのボリュームしか作れませんでした。 検索インデックスのデータ量の増え方は不規則なので、どれくらいで1TBに達するかを読むのが難しい。 メールの流通量も右肩上がりなので、常に1TBの制限を気にするのは、運用コストが高く、現実的ではありませんでした。

書き込み増加、読み込み負荷増加

メールの流通量が増えるにしたがって、当然書き込みの量も増えてきます。 書き込みが増えるにしたがって、I/O負荷が上がり、読み込みが快適に行えなくなるケースが増えてきました。

過去データを別の場所に

過去のインデックスに関しては、それほど頻繁にアクセスがあるわけではありません。 ですが、データ量も多いのでたまにアクセスがくると、キャッシュに大量のデータがのってしまい、本当に必要な直近のデータのキャッシュが追い出されてしまいます。 そこで、過去のデータに関しては、まとめて別の場所に置くのがいいのではないかと考えました。

当初、過去データも同じく mongodb に置こうかと考えていましたが、データ量が多いので、どうしてもメモリ量の多い高価なサーバを使う必要がでてきます。 過去データは、そんなにアクセスがあるわけではないので、高価なサーバを使うのももったいないので、他に良い場所はないか検討しました。

そうだ S3 に置こう!!

検索インデックスのデータはNグラムになっているので、文字単位でディレクトリを作成した中にデータを置いておけば、検索は問題なくできます。 S3にデータを置けば、サーバスペックを気にする必要もありません。 それにデータ容量を気にする必要もありません!!

S3 は POST の料金が高い!!

やれやれこれで大丈夫かと思いきや、S3 は POST の料金が高めに設定されているので、真面目に1ファイルずつ POST していくと、大変な金額になってしまいます。 何のために S3 を選択したんだ!!

ちなみに S3 での GET, POST の料金体系はこんな感じになってます。

料金
GET $0.0037/10,000req
POST $0.0047/1,000req

POSTはGETの12.7倍高い!!

軽く計算したみたところ、中規模の会社のデータを1ヶ月分POSTすると $14 かかることが分かりました。 これを全社分やることを考えると、大変な金額になってしまいます。

アーカイブしてファイル数減らせばいいんじゃね

過去のデータに関しては更新処理は発生しません。 それならば、アーカイブファイルにしてまとめておけば POST の回数を劇的に減らせます。 アーカイブファイルの中身は、HTTP GET で Range パラメータを指定すれば任意の範囲のバイト列が取り出せます。

GETの回数が増えるのは問題ありません。 GETはかなり安いので、多少増えてもPOSTの回数が減る事の方がメリットが大きくなります。

アーカイブ形式の選択

次はアーカイブ形式の検討です。 アーカイブファイルは次のような条件を満たす必要があります。

  • ファイル単位で取り出す事が容易できる
  • 目的のファイルがどこにあるかを容易に特定することができる

独自形式

自分たちで都合の良い形式にできるので、柔軟な構成にできます。 ただ全て自前で実装しないといけないので、どうしても開発工数がかかります。

tar

インデックスがないので、ファイル単位で取り出す事ができません。

ext2(等のファイルシステム)

ファイルシステムそのものをダンプしたデータも考えましたが、フラグメントがあって1回で取得できないのは困ります。

zip(zip64)

末尾にインデックスがあるので、任意のファイルを取り出すのが容易にできます。 zip64を使えば2GBの制限もなくなるので、問題ありません。

また既存のライブラリを使う事もできますので、開発工数も抑えられます。 実績のあるデータフォーマットで、既存のツールも流用できるメリットも大きい。

zipに決定

以上の事より、zipを採用する事に決定しました!!

HTTP GET Range で特定のファイルを取り出す

zipファイルは末尾にインデックスがあります。

zipファイルフォーマット

インデックスの大きさは、ファイル数によって変わってくるので、どこにインデックスがあるかは分かりません。 なので最初は適当に当りをつけてアクセスします。 インデックスの先頭には、かならず central file header signature(0x02014b50) という4バイトのデータが入ります。 これを目印にインデックスがどこから始まるかが分かります。

インデックスのデータがとれれば、個別のファイルがどこにあるかが分かりますので、HTTP GET Range で範囲を指定すれば任意のファイルを取り出す事ができます。 最低2回、多くても数回の GET アクセスで、ファイルを取得できます。

結論

S3にファイルを大量に書き込むときは、zipでアーカイブして、バイナリアクセスで取り出せば、サーバ代を節約できる。