AWS SDK for PHP v3のMultipart Upload機能を試してみた
望月@シアトルです。24時間体制でブログを書くためにシアトルに飛ばされました。
少し前の話ですが、AWS SDK for PHPのVersion3が正式リリースされました。Version3の新機能の中で一つ目を引くものがありました。Amazon S3 Multipart Uploadsです。
Multipart Uploadを利用することで、巨大なファイルの分割アップロードによる並列性の向上、処理速度上昇、及びアップロードの中断/再開が可能になります。
Multipart UploadはもともとS3には機能としては備わっていますが、この機能を活用するためにはクライアントプログラム側で上述の特徴を活かすようなコードを記述しなければならず、活用するための敷居が少し高かったです。今回のリリースにより、これをSDKレベルでサポートしてくれたようです。素晴らしいですね。
というわけで、今日はMultipart Uploadを試してみました。
前提
AWS SDK PHPの動作にはPHP 5.5以上が必要です。私の手元の環境(Mac OS X Yosemite)はPHP 5.5.20がインストールされていたため特にアップデートは必要ありませんでしたが、自身のPHPのバージョンを確認しておいてください。
以前のバージョンと同様に、Composerを使ってインストールします。
~/tmp/$ php -v PHP 5.5.20 (cli) (built: Feb 25 2015 23:30:53) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies ~/tmp/$ mkdir php3 && cd php3 ~/tmp/php3$ vim composer.json ~/tmp/php3$ cat composer.json { "require": { "aws/aws-sdk-php": "3.*" } } ~/tmp/php3$ curl -sS https://getcomposer.org/installer | php #!/usr/bin/env php All settings correct for using Composer Downloading... Composer successfully installed to: /Users/mochizukimasao/tmp/php3/composer.phar Use it: php composer.phar ~/tmp/php3$ php composer.phar install Loading composer repositories with package information Installing dependencies (including require-dev) - Installing mtdowling/jmespath.php (2.2.0) Downloading: 100% - Installing guzzlehttp/promises (1.0.0) Downloading: 100% - Installing psr/http-message (1.0) Downloading: 100% - Installing guzzlehttp/psr7 (1.0.0) Downloading: 100% - Installing guzzlehttp/guzzle (6.0.1) Downloading: 100% - Installing aws/aws-sdk-php (3.0.3) Downloading: 100% Writing lock file Generating autoload files ~/tmp/php3$ ls total 2200 drwxr-xr-x 7 mochizukimasao staff 238 6 4 13:00 . drwxr-xr-x 60 mochizukimasao staff 2040 6 4 12:54 .. -rw-r--r-- 1 mochizukimasao staff 60 6 4 12:54 composer.json -rw-r--r-- 1 mochizukimasao staff 12010 6 4 12:57 composer.lock -rwxr-xr-x 1 mochizukimasao staff 1105630 6 4 12:55 composer.phar drwxr-xr-x 9 mochizukimasao staff 306 6 4 12:57 vendor
実装
上述のドキュメントに従って簡単なサンプルを書いてみました。
<?php require 'vendor/autoload.php'; use Aws\S3\S3Client; use Aws\S3\MultipartUploader; use Aws\Exception\MultipartUploadException; $source_file = '10mega.data'; $s3client = new S3Client([ 'version' => 'latest', 'region' => 'ap-northeast-1' ]); $uploader = new MultipartUploader($s3client, $source_file, [ 'bucket' => 'mochizuki-example', 'key' => '10mega.data', ]); try { $uploader->upload(); echo "Upload complete.\n"; } catch (MultipartUploadException $e) { echo $e->getMessage() . "\n"; }
これだけでMultipart Uploadが実現できます!簡単ですね。ただし、アップロード中にN/Wの不調などが発生してしまってアップロードが中断されてしまった際には、500MB中の499MBまでアップロードが完了していたとしても全てロールバックされてしまいます。SDKではアップロードに失敗した時にMultipartUploadExceptionが投げられるので、そのExceptionに対して適切に処理を記述すればエラーが発生したとしても継続してアップロードを実行することが可能です。
エラー処理
上のコードのアップロード部分を、以下のとおり置き換えます。このコードもドキュメントに記載のものです。
do { try { echo 'upload start.'."\n"; $result = $uploader->upload(); } catch (MultipartUploadException $e) { echo $e->getMessage()."\n"; sleep(5); $uploader = new MultipartUploader($s3client, $source_file, [ 'bucket' => 'mochizuki-example', 'key' => '10mega.data', 'state' => $e->getState(), ]); } } while (!isset($result)); echo 'upload complete.'."\n";
変更点としては、MultipartUploadExceptionをcatchした際に、再度ExceptionのgetStateを取得し、それをコンストラクタに渡してMultipartUploaderオブジェクトを再作成しています。そしてアップロードが完了するまでループで処理を継続するようにしています。これにより、途中でExceptionが発生したとしても処理を継続させることができるようになりました。
アップロードのエラーを再現するため、アップロード実行中にクライアント端末のWi-Fiを一時的にOffにします。想定では、N/Wが不調でExceptionが発生したとしてもリトライ処理が走るはずです。
upload start. # ここでWiFiをOFF An exception occurred while uploading parts to a multipart upload. The following parts had errors: - Part 2: Error executing "UploadPart" on "https://s3-ap-northeast-1.amazonaws.com/mochizuki-example/10mega.data?partNumber=2&uploadId=5on.MntsoHsdMbRoByKdvvfqfbJAveLrBzbwxGSQVGU_EuCZDwhhhrmSq4bkaR.DsjDOds2rgXsAQGmVjwEYERDjQm_Fll4AaU8IgE.OuRoPtPMOkd5cqH3Kx4omZN7pZTwE2pikj.w75LalSryGnA--"; AWS HTTP error: cURL error 56: SSLRead() return error -36 (see http://curl.haxx.se/libcurl/c/libcurl-errors.html) (server): 100 Continue - - Part 1: Error executing "UploadPart" on "https://s3-ap-northeast-1.amazonaws.com/mochizuki-example/10mega.data?partNumber=1&uploadId=5on.MntsoHsdMbRoByKdvvfqfbJAveLrBzbwxGSQVGU_EuCZDwhhhrmSq4bkaR.DsjDOds2rgXsAQGmVjwEYERDjQm_Fll4AaU8IgE.OuRoPtPMOkd5cqH3Kx4omZN7pZTwE2pikj.w75LalSryGnA--"; AWS HTTP error: cURL error 56: SSLRead() return error -36 (see http://curl.haxx.se/libcurl/c/libcurl-errors.html) (server): 100 Continue <...エラーが続く...> # WiFiをONにする upload start. upload complete.
正常にアップロードが再開されたのが確認できました。$e->getState()の結果をシリアライズして保存しておけば別プロセスからのアップロード再開などもできるようなので、これはまた試してみたいと思います。
まとめ
PHP SDK version 3の新機能「Multipart Uploadサポート」のご紹介でした。この他にも魅力的な機能がありますので、これから新規開発する時にはPHP SDK v3を利用してみてはいかがでしょうか!
おまけ
今の時期のシアトルの気候は最高です。