5.4.1. アップロードファイル管理¶
目次
5.4.1.1. Overview¶
本ガイドラインでは、Amazon Simple Storage Service(以降、S3)を使用した仮アップロードファイルの保存方法について説明する。
Note
本ガイドラインでは、アップロードファイルをS3のストレージに保存する方法および留意点のみを説明する。
AWS環境におけるファイルアップロードの実装方法は Macchinetta Server Framework for Java (1.x) Development Guideline ファイルアップロード に記載の内容と基本的に同様であり、アップロードファイルの保存先をAWSが提供するストレージサービスであるS3に保存する点のみが異なる。
Note
本ガイドラインでは、仮アップロードを目的としたオブジェクト保存方法の説明に主眼を置くため、S3のオブジェクトのバージョニングについては考慮しない。
AWS環境では、Auto Scalingを使用した動的なスケーリングが可能である。 そのため、仮アップロードファイルはローカルストレージに保存せず、APサーバ外のストレージに保存する必要がある。 AWS環境では、ストレージサービスとしてS3が提供されているため、仮アップロードファイルの保存先として活用できる。 アプリケーションからS3へのアクセスは、Spring Cloud AWSまたはAmazon SDK for Javaを使用して行う。
5.4.1.1.1. アプリケーションからS3へのアクセス¶
アプリケーションからS3へアクセスする仕組みは以下の通り。
項番 | 説明 |
---|---|
(1)
|
S3へアクセスを行うクラスにインジェクションした
SimpleStorageResourceLoader またはPathMatchingSimpleStorageResourcePatternResolver を使用し、SimpleStorageResource を取得する。取得を行う際、内部的にはAmazon SDK for Javaの
AmazonS3Client を呼び出している。 |
(2)
|
アプリケーションは
SimpleStorageResource を使用してS3へのアクセスを行う。 |
(3)
|
SimpleStorageResource はAmazonS3Client を使用してS3へのアクセスを行う。 |
(4)
|
オブジェクトの削除などの保存/取得以外の操作を行う場合、S3へアクセスを行うクラスに
AmazonS3Client をインジェクションして使用する。 |
(5)
|
AmazonS3Client はS3に対してHTTPリクエストによるオブジェクト操作を行う。 |
5.4.1.2. How to use¶
5.4.1.2.1. ライブラリの使い分け¶
S3へのアクセスはSpring Cloud AWSまたはAmazon SDK for Javaを使用することで実装可能であるが、両者の使い分けについて説明する。
Spring Cloud AWSによる実装では、Spring Frameworkが提供するResource
インタフェースによるリソースアクセスの抽象化が利用可能である。
そのため、実装の標準化の観点からSpring Cloud AWSを使用して実装可能な機能については同ライブラリを使用して実装することが望ましい。
Resource
インタフェースの詳細については、Spring Framework Reference Documentation Resources を参照されたい。
ただし、Spring Cloud AWSでは以下のオブジェクト操作のみ実装可能である。
- S3へのオブジェクト保存
- S3からのオブジェクト取得
- AntパターンによるS3内のオブジェクト検索
オブジェクトの削除やバケット操作などのSpring Cloud AWSでは実装不可能な機能についてはAmazon SDK for Javaを直接使用する必要がある。
Note
ライブラリを併用する場合には実装が煩雑となるため、S3へのアクセスを行う部分はHelperクラスを作成して実装を集約することが望ましい。 ファイル操作の実装方法については ファイル操作の実装を参照されたい。
Note
Spring Cloud AWSではS3へのアクセスを行う際にs3://
をプレフィックスとするバケット名とオブジェクトキーを含む文字列を使用する。
例)s3://myBucket/myDirectory/myObject.txt
一方、Amazon SDK for Javaでは、バケット名とオブジェクトキーをそれぞれ指定する必要がある。
- バケット名 : myBucket
- オブジェクトキー : myDirectory/myObject.txt
Helperクラスを作成する際は留意すること。
5.4.1.2.2. Spring Cloud AWSの利用¶
5.4.1.2.2.1. 依存ライブラリの追加¶
Spring Cloud AWSを利用したS3へのアクセスを行うための依存ライブラリの追加を行う。
xxx-domain/pom.xml
<!-- (1) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-context</artifactId> </dependency>
項番 説明 (1)spring-cloud-context
の依存関係を追加する。
5.4.1.2.2.2. アプリケーションの設定¶
Spring FrameworkのResource
インタフェースを利用したS3へのアクセスを行うためのBean定義を行う。
Bean定義の詳細については、 Spring Cloud AWS Resource handling を参照されたい。
xxx-domain/src/main/resources/META-INF/spring/xxx-domain.xml
<!-- (1) --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aws-context="http://www.springframework.org/schema/cloud/aws/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cloud/aws/context http://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd"> <!-- (2) --> <aws-context:context-resource-loader/>
項番 属性名 内容 (1)xmlns:aws-contextAWS Context Namespaceを定義する。値としてhttp://www.springframework.org/schema/cloud/aws/context
を指定する。xsi:schemaLocationスキーマのURLを指定する。値にhttp://www.springframework.org/schema/cloud/aws/context
とhttp://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd
を追加する。(2)-<aws-context:context-resource-loader/>
を利用してResourceLoader
インタフェースを利用したS3へのアクセスを有効化する。
Note
Spring Cloud AWSを利用するための設定を行うことでAmazon SDK for Javaを利用するための設定も包含されるため、追加の設定は不要である。
5.4.1.2.2.3. マルチパートアップロードの利用設定¶
Spring Cloud AWSでは、S3の機能であるマルチパートアップロード(大容量オブジェクトの分割アップロード)をサポートしている。 S3のマルチパートアップロードについては Amazon Simple Storage Service 開発者ガイド マルチパートアップロードの概要 を参照されたい。
前述の設定に加えて以下の設定を行うことでマルチパートアップロードを有効にすることが出来る。
xxx-domain/src/main/resources/META-INF/spring/xxx-domain.xml
<!-- (1) --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aws-context="http://www.springframework.org/schema/cloud/aws/context" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cloud/aws/context http://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> <!-- (2) --> <aws-context:context-resource-loader task-executor="executor" /> <task:executor id="executor" pool-size="10" queue-capacity="0" rejection-policy="CALLER_RUNS" />
項番 属性名 内容 (1)xmlns:taskTask Namespaceを定義する。値としてhttp://www.springframework.org/schema/task
を指定する。xsi:schemaLocationスキーマのURLを指定する。値にhttp://www.springframework.org/schema/task
とhttp://www.springframework.org/schema/task/spring-task.xsd
を追加する。(2)-マルチパートアップロードを行うためのtask-executor
を定義する。
詳細については Spring Cloud AWS 9.3.1. Uploading multi-part files を参照されたい。
Warning
マルチパートアップロードを有効にしている場合、
- 5MB未満のファイルの場合:同期アップロード
- 5MB以上のファイルの場合:5MB毎にマルチパートアップロード
が行われる。 設定したpool-sizeを上限に、5MB毎にスレッドが作成される。 5MBのしきい値は外部から変更することはできない。
各スレッド毎に最大5MBのメモリ消費が発生するため、サイズの大きなファイルの保存を行う場合は留意すること。
また、キューイングされたリクエストもメモリを消費するため、queue-capacity
の値にも留意する必要がある。
マルチパートアップロードの設定を行っていない場合は常に同期アップロードが実行される。
5.4.1.2.2.4. ファイル操作の実装¶
仮アップロードを行う際のファイル操作の実装方法について説明する。
S3へのオブジェクト保存【Spring Cloud AWSを使用】
S3バケット上の一時ディレクトリにオブジェクトを保存する。
@Inject private ResourceLoader resourceLoader; // (1) // omitted MultipartFile uploadFile = memberRegisterForm.getUploadFile(); String bucketname = "myBucket"; String objectKey = "tmpDirectory/uploadFile_" + UUID.randomUUID().toString() + ".jpg"; WritableResource resource = (WritableResource) this.resourceLoader.getResource("s3://" + bucketname + "/" + objectKey); // (2)(3) try (InputStream inputStream = uploadFile.getInputStream(); OutputStream outputStream = resource.getOutputStream()) { // (4) IOUtils.copy(inputStream, outputStream); } catch (IOException e) { // omitted }
項番 説明 (1)ResourceLoader
のインジェクションを行う。<aws-context:context-resource-loader/>
が有効である場合、ResourceLoader
としてPathMatchingSimpleStorageResourcePatternResolver
が使用される。 (2) S3へ保存するファイルパスを指定する。PathMatchingSimpleStorageResourcePatternResolver
はs3://
の接頭辞が付与されたパスをS3へのアクセスと判断する。 (3)WritableResource
を取得する。S3へのアクセスを行う場合、WritableResource
としてSimpleStorageResource
が取得される。 (4)WritableResource
に対して書き込みを行うことでS3へのファイルアップロードを行う。本ガイドラインでは、org.apache.commons.io.IOUtils
を使用して書き込みを行っている。
Warning
S3のデータ整合性モデルについて
S3では、高い可用性を実現するために、複数のサーバ間でレプリケーションを行っている。 そのため、オブジェクトに対する変更が完全に反映されるまでの間に、変更を反映中のオブジェクトに対する参照を行った場合に意図しない結果が返却される可能性がある。 S3へのアクセスを実装する際は、S3が提供するデータ整合性モデルを踏まえた実装を行う必要がある。 S3のデータ整合性モデルについては、 Amazon Simple Storage Service ドキュメント 開発者ガイド Amazon S3 のデータ整合性モデル を参照されたい。
S3では、PUTおよびDELETEの上書きについては結果整合性、オブジェクトの新規作成については書き込み後の読み込み整合性が提供される。
従って、ファイルの更新を行う場合はオブジェクトキーを変更して別のS3オブジェクトとしてPUTしたものを参照させることで更新前のファイルの参照を防ぐことが可能となる。
その場合、オブジェクトキーにUUID
を含めるなどでオブジェクトキーが重複しないように留意する必要がある。
S3からのファイル取得【Spring Cloud AWSを使用】
S3バケット上の一時ディレクトリに保存したオブジェクトを取得する。 その後、仮アップロード時と同様に取得したオブジェクトを最終的な保存ディレクトリに保存する。
@Inject private ResourceLoader resourceLoader; // (1) // omitted Resource resource = this.resourceLoader.getResource("s3://" + bucketname + "/" + objectKey); // (2) // omitted
項番 説明 (1)ResourceLoader
のインジェクションを行う。 (2) S3上のパスを指定し、Resource
を取得する。取得したResource
に対して必要な処理を行う。Note
S3から取得したファイルをユーザにダウンロードさせる方法については、 Macchinetta Server Framework for Java (1.x) Development Guideline ファイルダウンロード を参照されたい。
S3上の単一ファイル削除【Amazon SDK for Javaを使用】
アップロードファイルの保存後、S3バケット上の一時ディレクトリに保存したオブジェクトを削除する。
@Inject private AmazonS3 s3client; // (1) // omitted s3client.deleteObject(bucketname, objectKey); // (2)
項番 説明 (1)AmazonS3
のインジェクションを行う。ResourceLoader
インタフェースを利用するために<aws-context:context-resource-loader/>
を有効にしている場合、ContextResourceLoaderBeanDefinitionParser
によりBean定義されたAmazonS3Client
が使用される。 (2) バケット名、オブジェクトキーを指定してファイルの削除を行う。
5.4.1.3. How to extend¶
5.4.1.3.1. 仮アップロード以外のファイル操作¶
代表的なファイル操作の例を以下に示す。
S3内のAntパターンによるオブジェクト検索【Spring Cloud AWSを使用】
@Inject private ResourcePatternResolver resourcePatternResolver; // (1) // omitted Resource[] result = resourcePatternResolver.getResources("s3://myBucket/*"); // (2) // omitted
項番 説明 (1)ResourcePatternResolver
のインジェクションを行う。ResourceLoader
インタフェースを利用するために<aws-context:context-resource-loader/>
を有効にしている場合、ContextResourceLoaderBeanDefinitionParser
によりBean定義されたResourcePatternResolver
が使用される。 (2) S3のパスを指定し、Resource
を配列形式で取得する。検索に使用する文字列はAntパターンで指定する。
S3上の複数ファイル削除【Amazon SDK for Javaを使用】
@Inject private AmazonS3 s3client; // (1) // omitted //(2) List<String> deleteKeyList = new ArrayList<String>(); // omitted List<KeyVersion> targetKeys = new ArrayList<KeyVersion>(); for (String deleteKey : deleteKeyList) { targetKeys.add(new KeyVersion(deleteKey)); } //(3) DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest("myBucket"); deleteObjectsRequest.setKeys(targetKeys); s3client.deleteObjects(deleteObjectsRequest);
項番 説明 (1)AmazonS3
のインジェクションを行う。 (2) 削除対象オブジェクトキーのリストを生成する。 (3) 削除対象のバケット名を指定してDeleteObjectsRequest
を生成し、削除対象オブジェクトキーのリストを設定してファイルの削除を行う。
Note
AmazonS3Client
を使用する場合、ファイル削除の他にもバケット操作などのS3上の様々な操作が可能である。
AmazonS3Client
の詳細についてはAmazonS3Client
の JavaDoc を参照されたい。
5.4.1.3.2. 仮アップロード時の不要ファイルのHousekeeping¶
仮アップロードの仕組みを使用してファイルのアップロードを行う場合に必要なHousekeepingについては、S3の仕組みを利用して行うことができる。
5.4.1.3.2.1. ライフサイクル管理の利用¶
S3では、バケット内のオブジェクトに対してライフサイクルを指定することができる。 ライフサイクル設定を利用して、作成から一定期間を経過したファイルのアーカイブや削除を行えるため、この機能を利用してHousekeepingを行う。
ライフサイクル管理の詳細については、 Amazon Simple Storage Service 開発者ガイド オブジェクトのライフサイクル管理 を参照されたい。
Note
ライフサイクル管理において指定可能なターゲット(対象オブジェクト)は、バケット全体もしくはプレフィックス指定による絞込のみである。 ワイルドカードによる指定などの複雑な制御は行えないため、バケットの構成やオブジェクトの配置に留意すること。
また、ターゲットに末尾が”/”であるプレフィックスを指定する場合、フォルダ配下のオブジェクトだけではなく、フォルダも削除される。
Note
ライフサイクル管理でHousekeepingの要件を満たせない場合は、オブジェクトの削除機能を実装する必要がある。実装方法については Macchinetta Server Framework for Java (1.x) Development Guideline 仮アップロード時の不要ファイルのHousekeeping を参照されたい。
5.4.1.4. Appendix¶
5.4.1.4.1. 高いリクエストレートが要求される場合の留意事項¶
Amazon Simple Storage Service 開発者ガイドにおいて、リクエストレートが高い場合のオブジェクトキーの付与についてのガイドラインが記載されている。
Amazon Simple Storage Service 開発者ガイド リクエスト率およびリクエストパフォーマンスに関する留意事項
上記のガイドラインに従うことで、パフォーマンスの低下を防ぐことが可能である。