AWS S3をJavaで

JavaでAWS S3を試す

AWS S3のパフォーマンス測定を行うため、JavaでS3の操作をしてみました。

準備

事前準備として以下のSDKやらライブラリを事前に用意します。

Java 用 AWS SDKは読んで時のごとく、JavaでAWSを操作するためのSDKです。
Apache HttpComponents Clientは↑を使うために必要です。

次に必要な情報として、AWSのセキュリティ証明書のページでaccess key IDとSecret access keyを用意しておきます。

最後にAWSのManagement ConsoleでBucketを作っておきます。
Bucketはそう繰り返し作るものでもないので、Javaでやらなくても良いでしょ?

Bucketリストを取得

まずは接続テストを兼ねてBucketリストを取得してみます。
以下のようにS3Test.javaを書きます。

package s3test;

import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;

public class S3Test {

  static void getList(AmazonS3 s3){
    for(Bucket bucket:s3.listBuckets()){
      System.out.println(bucket.getName());
    }
  }
  
  public static void main(String[] args) {
    
    System.out.println("START");
    AmazonS3 s3 = null;
    try {
      s3 = new AmazonS3Client(new PropertiesCredentials(
            S3Test.class.getResourceAsStream("AwsCredentials.properties")));
    }catch(Exception e){
      System.err.println(e.getMessage());
      System.exit(1);
    }
    
    System.out.println("======= Bucket List ========");
    getList(s3);
  }
}

そして、そのjavaファイルと同じディレクトリにAwsCredentials.propertiesというaccesskeyとSecretKeyが書いてあるファイルを置きます。

accessKey = xxxxxxxxxxxxxxxxxxxxxx
secretKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

適当にコンパイルして、実行してみます。

$ java -jar s3test.jar
START
======= Bucket List ========
your-original-bucket

アップロードするファイルの準備

ファイルアップロードを実装する前にローカルの環境にアップロードするファイルを用意しておきます。
Javaでそこからやっても良いのですが、面倒なので事前に用意することにしました。
種となる10KBのファイルを用意します。

$ i=0; while [ $i -lt 1024 ]; do echo -n '0123456789' >> orig01; i=$(($i+1)); done
$ cat orig01
012345678901234567890123456789012345678901234567890123456789
.
.
.

そしてこの種ファイルで10KBのファイルを量産します。

$ mkdir /var/tmp/files
$ cd /var/tmp/files
$ i=0; while [ $i -lt 300 ]; do cp orig01 test-${i}.txt; i=$(($i+1)); done

とりあえず、test-??.txtというファイルを300個作りました。

ファイルのアップロード

アップロードするファイルができましたのでさっそくファイルのアップロードを実装します。
冒頭で書いた通り、今回の目的はパフォーマンステストなので並列でアクセスできるようにthreadで実装します。

class S3TestThread implements Runnable {
  
  String mode = "";
  int index = 0;
  String localPath = "/var/tmp/files";
  String filePrefix = "test-";
  String bucket = "your-original-bucket";
  String s3Path = "test01/" + filePrefix;
  AmazonS3 s3;
  long start, end;
  
  S3TestThread(AmazonS3 s, String m, int i){
    s3 = s;
    mode = m;
    index = i;
  }
  
  void uploadFile(int i){
    
    // uploadするファイル
    File localFile = new File(localPath + "/" + filePrefix + i + ".txt");
    String s3File = s3Path + i + ".txt";
    
    System.out.println("UploadFile: " + localFile.getName());
    
    // 時間計測用のスタート時間
    start = System.currentTimeMillis();
    
    // upload
    s3.putObject(bucket, s3File, localFile);
    
    //時間計測用終了時間
    end = System.currentTimeMillis();
    
    //処理時間出力
    System.out.println(s3File + ":" + (end - start));
    
    //認証無しでアクセスできるように設定(GETのパフォーマンステスト用)
    s3.setObjectAcl(bucket, s3File, CannedAccessControlList.PublicRead);
    
  }
  
  @Override
  public void run(){
    if(mode.equals("put")){
      uploadFile(index);
    }
  }
}

コンストラクタではs3の接続オブジェクトと、動作モード(今回はput)、そしてthreadのインデックスを渡すようにしました。
動作モードについてはこれからdeleteなども必要になるかもしれないので、そのためのスイッチ。
そして、パフォーマンスを測るためにuploadする前と後で時間を取ります。
最後にGETのパフォーマンス測定はApache JMeterを使いたいのでACLをPublicReadに設定しています。

mainは省略。

実行結果は以下の通り。

$ java -jar s3test.jar 10 put
START
=======put==========
UploadFile: test-0.txt
UploadFile: test-1.txt
UploadFile: test-2.txt
UploadFile: test-3.txt
UploadFile: test-4.txt
UploadFile: test-5.txt
UploadFile: test-6.txt
UploadFile: test-7.txt
UploadFile: test-8.txt
UploadFile: test-9.txt
test01/test-2.txt:1575
test01/test-3.txt:1580
test01/test-8.txt:1584
test01/test-1.txt:1591
test01/test-4.txt:1588
test01/test-6.txt:1588
test01/test-9.txt:1610
test01/test-7.txt:1615
test01/test-5.txt:1621
test01/test-0.txt:1638

まとめ

SDKがあるのでご覧の通りとても簡単。
ちなみにSDKはJavaだけでなくPythonもあるので、機会があればそっちもやってみたいです。

おしまい。