複数のクラウドサービス間でオブジェクトストレージの中身を同期する
こんにちは。インフラストラクチャー部の加藤(@EugeneK)です。
クックパッドのすべてのレシピやつくれぽ等の画像はAmazon Web Services(以下AWS)のSimple Storage Service(以下S3)にオブジェクトとして保存されています。
S3は99.999999999%の堅牢性と99.99%の可用性を謳っていますが、ユーザさんから預かった大切なデータを守るため、万一に備えて別のクラウドストレージにもバックアップを行っています。
今回はそのオブジェクトを準リアルタイムでGoogle Cloud Storage(以下GCS)に同期されるようにした話をします。
S3にオブジェクトが追加されたことを知る
S3にはEvent Notificationという機能があります。 この機能を用いると、S3のバケット内のオブジェクトが追加・更新・削除されたときに通知イベントを発行することができます。 イベントの発行先は以下の3つから選択できます。
- Simple Notification Service(SNS)のトピック
- Simple Queue Service(以下SQS)のキュー
- Lambda
今回はSQSを発行先として選択しました。
SQSのキューからメッセージを取得する
SQSは名前の通りシンプルなメッセージキューサービスで、Amazon Web Servicesの各種サービスの中でも古くからあるものです。 S3のバケットに対する変更は先の通知イベントにより、SQSのメッセージとしてキューイングされます。 Elastic Compute Cloud(以下EC2)で作成したインスタンスでこのキューからメッセージを1つずつ取得することで、S3バケットに対する変更の内容を知ることができます。
S3の内容をGCSに反映する
EC2のインスタンスはメッセージの中身を読み取って、その情報を元にS3からオブジェクトを読み出してGCSに反映させます。
たったこれだけで「複数のクラウドサービス間でオブジェクトストレージの中身を同期する」ことができるようになりました。
細かい工夫
本筋からは離れますが、便利な機能を使用しているのでここで紹介します。 通常、AWSのAPIを利用するときはアクセスキーIDとシークレットアクセスキーのペアからなるクレデンシャルを用いることが多いですが、EC2のインスタンスにクレデンシャルの情報を持たせずにAPIを利用できるようにしました。
EC2のIAMロールという機能を用いると、ロールを紐付けたインスタンスは、自身のインスタンスメタデータから許可された権限を持つクレデンシャルを取り出すことができます。 ここでは、以下のAPIリクエストを許可するようにしたIAMロールを作成してインスタンスに関連付けました。
- SQSからのメッセージ取得(ReceiveMessage)
- 処理が完了したメッセージの削除(DeleteMessage)
- S3からのオブジェクトの取得(GetObject)
IAMロールを関連付けたインスタンスからAWS-SDKを使用したAPIリクエストを実行すると、AWS-SDKがクレデンシャルの取り出しをやってくれるので、クレデンシャルを意識する必要はなくなります。
過去分のデータを同期する
同期を開始するとそれ以降のデータは同期されますが、同期を開始する以前に既にS3に存在したデータをGCSにコピーする必要があります。 とはいってもわざわざ別の仕組みを用意する必要はなく、同期の仕組みをそのまま使います。
SQSのキューへのメッセージ発行はS3のイベント通知だけが行えるわけではありません。 バケット内にある全てのオブジェクトのリストを作成し、それらをメッセージとしてSQSのキューに発行してしまえば、あとはこれまでに作った仕組みが処理してくれます。 つまり、S3の通知イベントを模したメッセージをSQSに発行してやるだけです。
クラウドらしさを活かしたアーキテクチャ
この仕組みを用いて実際に約20TB(1500万オブジェクト)のデータの同期を行いました。 これだけのデータ量(特にオブジェクト数)となるとかなり長い時間がかかってしまいそうですが、スケールしやすいのがクラウドの強みですのでスケールで解決します。 EC2のインスタンスを複数並べて並列にコピーすることで時間を短縮することができます。
実際に、SQSやS3は同時に複数の処理を行うことが得意なサービスなので、1秒間に数千回もの処理を行っても何の問題もありませんでした。 具体的には50台のインスタンスを使っておよそ200並列で稼働させることで過去分のデータの同期が3日ほどで完了しました。
通常このような並列処理をするとなると、同じ処理が複数回実行されないように分割してやる必要がありますが、この仕組みはSQSを利用しているため必要ありません。 また、SQSには可視性タイムアウトという機能があり、処理途中に何らかの理由で失敗したときも、メッセージの削除を行わずに放置しておけば、しばらく経った後に同じメッセージが再取得できるようになるので結果的にリトライも自動的に行われます。
おわりに
複数のクラウドストレージ間でデータを同期する方法について紹介しました。同期以外にも様々な使い方に応用できると思います。 クラウドサービスが提供する個々のサービスを部品としてつなぎ合わせることで、堅牢で柔軟なシステムを最小限の手間で実現することが可能になります。
やりたいことに集中し、そのために必要となる前提の要素は用意されているコンポーネントを使用する、というのがクラウドサービスの最も良い使い方だと考えています。 ハードウェア資産を持たなくてよいということがクラウドの売りとされがちですが、本当のクラウドの強みはこういったところにあります。