Amazon Glacierを使ってみた


目次

みなさん、こんにちは!フリューでモバイルサイト開発を行っている鷲見といいます。今日はAWSの新しいサービスAmazon Glacierについて実際に触れて検証してみたのでその報告をしてみたいと思います。


Amazon Glacierとは

Amazon Glacier(以下、Glacier)とは2012年8月21日にAWSが発表した低コストなストレージサービスです。低コストと言われている通りなんと1GBあたり月額約1円($0.012/GB)で利用することができます。今まで安いと思っていたS3が1GBあたり約10円(最初の1TBまで$0.13/GB)なのでなんと、S3の10分の1程度のお値段で利用できます。まさに価格破壊のストレージサービスです。

ちなみに上記以外にはファイルのアップロード、ダウンロード、アーカイブデータの一覧取得のリクエストの回数に応じてお金がかかるのと、転送量に応じてお金がかかります。

ちなみに読み方は『グレイシャー』だそうです。


S3との違い

S3の約10分の1のお値段で利用できるならGlacierを使えばいいじゃんと思ってしまいそうです。S3とGlacierはどう違うのでしょうか?

GlacierのS3との違い

GlacierがS3と比べて違う点は

  1. ファイルのダウンロードを開始できるようになるまで時間がかかる
  2. 好きなファイル名をつけることはできずArchiveIdで管理される

の2点です。

特に1つ目の点がS3と違う大きな特徴です。

Glacierでは、ファイルの取得のためにジョブと呼ばれるものを開始します。ジョブはキューに保存され順番に処理が行われます。ジョブがキューから取り出され実行されて完了すると、ファイルがダウンロード出来るようになります。このファイルがダウンロードが出来るようになるまでの時間が4,5時間と言われています。

2つ目の特徴ですが、ファイルのアップロード時にArchiveIdと呼ばれるIDが付与されます。アップロード完了後、ファイルの取得・消去の際にはこのArchiveIdを指定する必要があります。よってこのArchiveIdがどのようなファイルと紐付けられているかを管理する必要がでてきます。

S3との使い分け

上記のようなGlacierの特徴を考えると、Glacierには頻繁に出し入れが発生するファイル、すぐにダウンロードできないと困るようなファイルはGlacierでの保存に向いていません。このようなデータは今までどおりS3に保存するべきでしょう。

逆に一度保存すると出し入れがほとんど発生しない、ダウンロードするのに時間がかかってもよいようなデータはGlacierでの保存に向いています。各種データのバックアップ・アーカイブなどのコールドデータの保存にはGlacierが向いています。

Glacierという名前は英語で「氷河」なので、そもそもコールドデータを保存するのに適したストレージであるということがネーミングにも込められているようです。


Glacierの使い方

Glacierの基本的な使い方は以下の様な感じになります。

1.Vaultの作成

Glacierを使うにはまずはVaultを作成する必要があります。Vaultは貯蔵庫を意味する英語で、S3でいうところのBucketに近い感じでしょうか。Vaultには任意の名前をつけることができるので、用途に応じたわかりやすい名前をつけるのが良いでしょう。

2.ファイルのアップロード

1で作成したVaultにファイルをアップロードします。GlacierではデータはすべてArchiveという名前で扱われ、アップロードされたファイルも以降はArchiveと呼ばれます。Archiveにはそれぞれに一意となるArchiveIdが割り当てられ、アップロード後はArchiveIdでデータを識別します。ファイルのアップロード時にArchiveIdが割り振られますので、ArchiveIdとファイルの紐付けを利用者側で行なっておく必要があります。

3.Archiveのダウンロード

2でアップロードされたArchiveをダウンロードします。ArchiveをダウンロードするにはまずはGlacierに対しデータの取得リクエストを送信し、ジョブを開始します。データ取得のためのジョブが完了するとジョブの結果をダウンロードできるようになります。このリクエストの送信から、ジョブの完了までおよそ4,5時間かかります。


サンプルプログラム

現在、Vaultの作成はManagementConsoleから行うことができますが、Archiveの操作やVault内のアーカイブ一覧の取得などはManagementConsoleでは行うことができません。このような操作はAPIから行う必要があります。今回はAWS SDK for Javaを使ってGlacierの基本的な操作を行なってみます。

※AWS SDK for Javaのバージョンが1.3.18より前だとGlacierに関するバグがあるようです。1.3.18以降のバージョンを利用するようにしてください。

Vaultの作成

まずはプロキシを使っている場合などはプロキシの設定を行います。

//Proxy情報の設定    
  ClientConfiguration clientConfiguration = new ClientConfiguration();
  clientConfiguration.setProxyHost("XX.XX.XX.XX");
  clientConfiguration.setProxyPort(XXXX);

次にGlacierを操作するためのクライアントを生成します。クライアント生成後エンドポイントを指定し、リージョンを設定します。

エンドポイントはこちらに整理されています。

AwsCredentials.propertiesにはアカウントのアクセスキーとシークレートキーを記入しておきます。 書き方はこちらを参照してください。

//Glacierクライアントの生成
  AWSCredentials credentials 
      = new PropertiesCredentials(
          VaultCreator.class.getResourceAsStream("AwsCredentials.properties"));
  AmazonGlacierClient client = new AmazonGlacierClient(credentials,clientConfiguration);
  client.setEndpoint("https://glacier.ap-northeast-1.amazonaws.com/");

Glacierのクライアントが生成できたので、Vaultの作成リクエストを生成し、クライアントから送信します。

//Vaultの作成
  CreateVaultRequest createVaultRequest 
      = new CreateVaultRequest().withVaultName("GLACIER_TEST");
  client.createVault(createVaultRequest);

これでVaultの生成は完了です。

次にVaultにたいしてArchive取得・Archive一覧取得のジョブが完了したときにSNSで通知を行うよう設定を行います。

ここでは予めSNSのTOPICを予め生成し、ARNを控えておきます。

//SNS通知設定(SNSトピックのARNの設定と、通知対象イベントの設定)
  VaultNotificationConfig vaultNotificationConfig         
      = new VaultNotificationConfig().withSNSTopic("SNS TOPIC の ARN") 
          .withEvents("ArchiveRetrievalCompleted","InventoryRetrievalCompleted");         
  SetVaultNotificationsRequest setVaultNotificationsRequest = new
      = new SetVaultNotificationsRequest().withVaultName("GLACIER_TEST") 
          .withVaultNotificationConfig(vaultNotificationConfig); 
  client.setVaultNotifications(setVaultNotificationsRequest);

withEventsに渡しているのは通知を行うイベントの種類で“ArchiveRetrievalCompleted”を指定するとArchive取得ジョブ完了時に、“InventoryRetrievalCompleted”を指定するとArchive一覧取得ジョブ完了時に通知が行われます。

これでSNSの設定も完了です。これでこのVaultに対するジョブ完了時に通知が行われます。

ファイルのアップロード

ファイルのアップロードにはArchiveTransferManagerを利用します。GlacierクライアントとCrendentialを渡してArchiveTransferManagerを生成し、uploadメソッドでファイルをアップロードします。

//ファイルのアップロード
  File uploadFile = new File("Path to Upload File");
  ArchiveTransferManager atm = new ArchiveTransferManager(client, credentials);
  UploadResult result 
      = atm.upload("GLACIER_TEST", "Archive upload test :upload time = "
           + (new Date()), uploadFile);
  System.out.prinltn("ArchiveId:"+result.getArchiveId());

uploadメソッドに渡している引数はVault名、Archiveの説明文,アップロード対象ファイルとなります。

これでファイルのアップロードは完了です。uploadメソッドの返り値として渡されるUploadResultにはアップロードしたファイルのArchiveIdが含まれています。アップロードしたファイルは今後ArchiveIdを指定して取得することになるので、ArchiveIdを必ず控えておくようにしましょう。

ちなみに200MBのファイルのアップロードにかかった時間は10回の平均で50.038秒でした。

Vault内のArchive一覧取得

現在Vaultの中に保存されているArchiveの一覧を取得します。こちらはArchive一覧取得ジョブを開始し、ジョブが完了後に、ジョブの結果をダウンロードするという流れになります。

ジョブの開始リクエストを生成し、GlacierクライアントのinitiateJobメソッドを呼び出します。

//一覧取得ジョブの開始
  InitiateJobRequest initiateJobRequest = 
      new InitiateJobRequest().withVaultName(vaultName)
          .withJobParameters(new JobParameters().withType("inventory-retrieval"));
  InitiateJobResult initiateJobResult = client.initiateJob(initiateJobRequest);
  System.out.println("initiate inventory-retrieval job:jobId="+initiateJobResult.getJobId());

このinitiateJobメソッドの返り値のInitiateJobResultに、開始したジョブのIDが含まれています。ジョブ完了後に結果をダウンロードするのに必要となるので、JobIdを控えておくようにしてください。

SNSにメールを登録していると、ジョブが完了すると以下の様なJSON形式の内容のメールが送信されます。

//JSONは見やすいように整形しています。
{
  "Action":"InventoryRetrieval",
  "ArchiveId":null,
  "ArchiveSizeInBytes":null,
  "Completed":true,
  "CompletionDate":"2012-08-28T13:03:12.135Z",
  "CreationDate":"2012-08-28T08:35:20.989Z",    
  "InventorySizeInBytes":3944,
  "JobDescription":null,
  "JobId":"OA18_Zj3XtGpqlCXRfd7XFL5ZLbfDTsuNXbB6GCt57LWIPHGy1vh_bGmVA-QM0YbAQl_XXXXXXXXXXXXXXXXXXXXXXXX",
  "SHA256TreeHash":null,
  "SNSTopic":null,
  "StatusCode":"Succeeded",
  "StatusMessage":"Succeeded",
  "VaultARN":"arn:aws:glacier:ap-northeast-1:XXXXXXXXXXXX:vaults/GLACIER_TEST"
}

ジョブが完了したことがメールからわかるのでジョブの結果をダウンロードすることができます。ちなみにジョブの結果をダウンロードできるのはジョブ完了後24時間以内ですので注意してください。ではジョブの結果をダウンロードしてみましょう。

GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest()
    .withVaultName("GLACIER_TEST")
        .withJobId("TARGET_JOB_ID");
  GetJobOutputResult getJobOutputResult = client.getJobOutput(getJobOutputRequest);
  InputStream resultStream = getJobOutputResult.getBody();
  File downloadFile = new File("path to output file");
  createFileFromInputStream(resultStream,downloadFile);       

Vault名とJobIdを指定してジョブの結果取得リクエストを生成し、GlacierクライアントのgetJobOutputメソッドを呼び出します。結果として渡されるGetJobOutputResultのgetBodyメソッドでInputStreamを取り出すことができます。このInputStreamを読み込むことでジョブの結果を読み込むことができます。InputStreamで読み込んだ内容をファイルに書きだすのが良いかと思います。

このcreateFileFromInputStreamメソッドはInputStreamで読み込んだ内容を引数で渡されたファイルに書き込んでいます。

実際に書きだされたファイルの中身は以下のようになります。

//JSONは見やすいように整形しています。
{
  "VaultARN":"arn:aws:glacier:ap-northeast-1:XXXXXXXXXXXX:vaults/GLACIER_TEST",
  "InventoryDate":"2012-08-24T22:55:17Z",
  "ArchiveList":[
    {
      "ArchiveId":"_qFsgmHVr7DPw1xe9eWCreWocaMAbUy0AEcyhvxkeyinzQF_z17kwKlRBotL2WZrX0r-oTYp1N1uuTDoYG4lfq6omu031s0YSwAjLN3ZvKR-cfjipTbWc3o94erbUQY9XXXXXXXXXX",
      "ArchiveDescription":"Archive upload test :upload time = Fri Aug 24 18:22:11 JST 2012",
      "CreationDate":"2012-08-28T08:35:20.989Z",
      "Size":209715200,
      "SHA256TreeHash":"c2c428dbf3728eeb184ef68ac069a28b189e2f4860e547f73ece62XXXXXXXXXX"
    }
  ]
}

Vault内にArchiveが複数ある場合は、”ArchiveList”の配列内にオブジェクトが複数格納されます。

ちなみに検証時は4時間から4時間30分までの間にジョブが完了していました。

Archiveのダウンロード(Low Level API)

Archiveのダウンロードは基本的にArchiveの一覧取得とほぼ同じ方法で行います。

違う点は対象のArchiveIdを指定するところ、withTypeで”archive-retrieval”をしているところとなります。

//アーカイブ取得ジョブの開始
  InitiateJobRequest initiateJobRequest = 
      new InitiateJobRequest().withVaultName("GLACIER_TEST")
          .withJobParameters(new JobParameters()
          .withArchiveId("TARGET_ARCHIVE_ID")
          .withType("archive-retrieval"));
  InitiateJobResult initiateJobResult = client.initiateJob(initiateJobRequest);
  String jobId = initiateJobResult.getJobId();
  System.out.println("initiate archive-retrieval job:jobId="+jobId);

 

SNSにメールを登録していると、ジョブが完了すると以下の様なJSON形式の内容のメールが送信されます。

//JSONは見やすいように整形しています。
{
  "Action":"ArchiveRetrieval",
  "ArchiveId":"_qFsgmHVr7DPw1xe9eWCreWocaMAbUy0AEcyhvxkeyinzQF_z17kwKlRBotL2WZrX0r-oTYp1N1uuTDoYG4lfq6omu031s0YSwAjLN3ZvKR-cfjipTbWc3o94erbUQY9XXXXXXXXXX",
  "ArchiveSizeInBytes":209715200,
  "Completed":true,
  "CompletionDate":"2012-08-27T11:45:01.139Z",
  "CreationDate":"2012-08-27T07:29:52.894Z",
  "InventorySizeInBytes":null,
  "JobDescription":null,
  "JobId":"T5ZRyg1tWFjSFWlEsxUpGjpXTXiYvo9iD3VM59-E34z-86Crs9bQDcVWKM8RERM09Q1Pd9Fel52HJuqI-GXXXXXXXXXX",
  "SHA256TreeHash":"c2c428dbf3728eeb184ef68ac069a28b189e2f4860e547f73ece62XXXXXXXXXX",
  "SNSTopic":"arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:glacier-archive-transfer-XXXXXXXXXXXXXXX",
  "StatusCode":"Succeeded",
  "StatusMessage":"Succeeded",
  "VaultARN":"arn:aws:glacier:ap-northeast-1:XXXXXXXXXXXX:vaults/GLACIER_TEST"
}

ジョブの結果のダウンロードはアーカイブ一覧の取得と全く同じ内容で、JobIdを変えて実行すればダウンロードすることができます。

ちなみに検証時はジョブが完了するまで4時間30分ほどでした。

Archiveのダウンロード(High Level API)

GlacierのAPIには通常のLowLevelAPIとより簡単に利用できるようになっているHighLevelAPIの2種類があります。ArchiveのダウンロードやアップロードにはHighLevelAPIを使うことができます。ここではHighLevelAPIを使ってArchiveをダウンロードしてみます。

//アーカイブ取得(High Level API)
  AmazonSQSClient sqs = new AmazonSQSClient(credentials, clientConfiguration);
  sqs.setEndpoint("https://sqs.ap-northeast-1.amazonaws.com");
  AmazonSNSClient sns = new AmazonSNSClient(credentials, clientConfiguration);
  sns.setEndpoint("https://sns.ap-northeast-1.amazonaws.com");
    
  ArchiveTransferManager archiveTransferManager = 
    new ArchiveTransferManager(client,sqs,sns);
  File downloadFile = new File("path to output file");
  archiveTransferManager.download("GLACIER_TEST", "TARGET_ARCHIVE_ID", downloadFile);

ファイルのアップロードと同様ArchiveTransferManagerを使うと簡単にダウンロードすることができます。ただ現在、US-EAST以外のリージョンで利用する場合はSNSとSQSのエンドポイントを個別に設定する必要があります。

ArchiveTransferManagerのdownloadメソッドが呼び出されるとジョブが開始され、ジョブが完了すると引数で渡したファイルにジョブ結果の内容が書き込まれます。なおジョブが完了し、結果をダウンロードし終わるまで制御が返って来ませんので、別スレッドにて実行するか、バックグラウンドで実行することをおすすめします。

ちなみにジョブ完了までの時間はLowLevelAPIとほぼ同じでした。

Jobの状態取得

SNSの設定を忘れてジョブを開始した場合、ジョブが完了したか実行中かわからないということもあるかと思います。そのような場合のためのジョブの現在の状態を取得することができます。

DescribeJobRequest describeJobRequest = 
      new DescribeJobRequest().withVaultName("GLACIER_TEST").withJobId("TARGET_JOB_ID");
  DescribeJobResult describeJobResult = client.describeJob(describeJobRequest);           
  System.out.println("JobId:"+jobId);
  System.out.println("Completed:"+describeJobResult.getCompleted());
  System.out.println("StatusCode:"+describeJobResult.getStatusCode());

ジョブ実行中の場合はgetCompleted()はtrue,getStatusCode()は”InProgress”を返します。

ジョブが完了している場合はgetCompleted()はfalse,getStatusCode()は”Succeeded”を返します。

これでジョブの現在の状態を把握することができます。


現在の注意点

1.ArchiveIdとファイル内容、JobIdとジョブ内容の紐付けが必要

ファイルはアップロードした時点でVault内のArchiveとして扱われ、アップロード以降ファイルの操作にはArchiveIdが必要となります。ArchiveIdとファイル内容を紐付けて管理しておかないと、どのArchiveIdのファイルがどのような内容かわからなくなってしまいます。

またArchiveの取得、Archiveの一覧取得時にジョブを開始した際、ジョブにJobIdが割り振られ、ジョブの結果をダウンロードする際にこのJobIdが必要となります、JobIdとジョブの内容を紐付けて管理しておかないと、どのジョブが、何をダウンロードしようとしていたのかがわからなくなってしまいます。

このあたりはSimpleDBに紐付けデータを保存しておくのが手間が少なくてスジがよさそうな気がしています。

2.Archiveの取得に時間がかかるうえ、期間内に取得しなければならない

ジョブの開始から完了まで検証中は4時間から4時間30分かかっていました。また、ジョブの結果は完了後24時間以内に取得する必要があります。SNSの設定を行なっているとジョブの完了時にメールが送信されるとはいえ、うっかりしているとダウンロードし忘れてしまいそうですね。ジョブのステータスを取得するプログラムを定期的に実行し、完了している場合はダウンロードするような仕組みがあるといいかもしれませんね。

3.詳細な利用にはプログラミングが必要

現在GlacierへのArchiveの保存、Archiveの取得などはAWS SDKを使ってプログラミングをしないと利用することができません。

Management Consoleでは8月31日現在ではVaultの作成と設定変更・削除のみが可能となっています。このあたりは今後のManagement Consoleの機能追加に期待したいところです。ちなみにS3との間でシームレスにデータを移動するためのオプションが追加される予定とのことなので、今後がとても楽しみです。


利用方法を検討してみる

では、実際にGlacierをどのように使うのかを考えてみます。

弊社ではファイル・データのバックアップに現在S3を利用しており、日次でデータをS3に転送しています。これが毎日続くとなると結構な容量と結構な金額となってしまいそうです。そこでGlacierを活用してみたいと思います。

まず今までの運用通り毎日のバックアップデータはS3に保存します。ただS3に保存後一定期間経過後のデータをGlacierに転送します。

そうするとS3に保存されているデータは常にほぼ一定の容量となります。そして価格の安いGlacier上にどんどんバックアップデータが蓄積されていきます。

今までS3に保存されていたデータをGlacierに移すことができるので、コスト削減が見込めそうですね。


まとめ

今回はAmazon Glacierの概要の説明とサンプルプログラムを解説してみました。

  • Amazon Glacierは1GBあたりの月額が約1円の超低コストストレージサービスです。
  • S3と比べ、ファイルのダウンロードを開始できるようになるまで時間がかかるなどの制限も多いです。
  • 操作にはAWS SDKを用いてプログラミングを行う必要があります。

というのがGlacierの特徴でした。

制限も多いですが、特徴を理解して利用できればかなりのコスト削減になるのではないかと思いますので、ぜひGlacierを利用してコスト削減にチャレンジしてもらいたいと思います。

今回一部公開しましたサンプルプログラムはこちら(GitHub)で公開していますので、ぜひ参考にしてみてください。