AWS CLI S3コマンドの並列処理設定

# 概要

`aws s3`コマンドの並列転送処理、マルチパートの処理を設定でコントロールできるようになった。

# S3コマンドの自動並列処理

AWS CLIでは、`aws s3`から始まる高レベルのコマンドがあり、S3のオブジェクトの操作が便利になっています。

- http://docs.aws.amazon.com/cli/latest/reference/s3/index.html

この中では、ワイルドカードを指定する、もしくは`sync`コマンドで、複数ファイル処理が行えます。
これらは並列で転送処理が行われるのですが、これ以外にも、アップロードする1つのファイルが大きい場合は、内部的にマルチパートに分割され、Multipart Uploadが行われています。
(`--debug`で動作を確認できます)

並列処理を行うことで、スループットを向上させることができる、またマルチパートの場合は、それに加えて、単一のファイルをPUTした際には通信経路の問題等で失敗してしまったときに全てやり直さないといけないのに比べ、マルチパートであればそのパートだけやり直すことでリカバリができるため、アップロードの安定性の面でもメリットがあります。

これらは、従来は、なんかいい感じに処理が行われていたのですが、例えばスループットが出すぎて他の通信を圧迫してしまう、頑張りすぎて通信元の負荷が高くなるといったことがありました。とはいえ、`aws s3api`の低レベルで並列処理を実装するのはめんどくさい。

# s3 コマンドの設定が追加された

AWS CLI 1.7系よりこの動作を変更できる設定項目が追加されています。

- [AWS CLI S3 Configuration](http://docs.aws.amazon.com/cli/latest/topic/s3-config.html)

(aws-cli 1.7.24 以降では、`aws help s3-config` でも説明を確認できます)

これで何ができるようになったかというと

- 同時並列通信数
- マルチパートに分割するファイルサイズの閾値、サイズ

が調整できるようになっています。

## つかいかた

以下のように `~/.aws/config` に記述する

```
[profile development]
aws_access_key_id=foo
aws_secret_access_key=bar
s3 =
  max_concurrent_requests = 20
  max_queue_size = 10000
  multipart_threshold = 64MB
  multipart_chunksize = 16MB
```

もしくは、`aws configure set` コマンドで設定する

```
$ aws configure set default.s3.max_concurrent_requests 20
$ aws configure set default.s3.max_queue_size 10000
$ aws configure set default.s3.multipart_threshold 64MB
$ aws configure set default.s3.multipart_chunksize 16MB
```

## 設定項目

<dl>
<dt>max_concurrent_requests</dt>
<dd>並列リクエストの最大数。デフォルト10。<br/>
複数のオブジェクトを転送する(PUT/GET)する場合や、マルチパートに分割した個々のパートをアップロードする際の同時の並列処理の数を設定します。</dd>
<dt>max_queue_size</dt>
<dd>タスクキューの最大サイズ。デフォルト1000。<br/>
内部動作として、一度キューに貯めて、executorにキューの内容を並列処理を行う流れとなっており、この数はそのキューに貯めこむ最大値。これを超える場合は、中身が捌けた後に再度キューに貯めこんで、と繰り返される。<br/>
この値はメモリにインパクトがあり、あまりいじる必要はなさそうだが、例えばすごく <code>max_concurrent_requests</code> が大きくて、キューが捌けるスピードが早い、みたいな状態だと意味はあるかもしれない。</dd>
<dt>multipart_threshold</dt>
<dd>ファイルをマルチパートに分割する閾値。デフォルト8MB。<br/>
8MBを超えたファイルがあると、マルチパートに分割をしてアップロードする。</dd>
<dt>multipart_chunksize</dt>
<dd>マルチパートの1パートあたりのサイズ。デフォルト8MB。</br>
マルチパートで処理すると判断した場合の分割サイズ。S3の仕様として、5MB〜5GBの範囲で指定可能。末尾は5MBに達してなくても許可される。<br/>
通信環境がよければ、8MBのサイズはちょっと小さいかもしれない。</dd>
</dl>

### 設定例

並列処理はしない。なるべくマルチパートも使わない

```
$ aws configure set default.s3.max_concurrent_requests 1
$ aws configure set default.s3.multipart_threshold 5GB
$ aws configure set default.s3.multipart_chunksize 5GB
```

# マルチパートアップロードの強制終了にご注意

マルチパートアップロードは、初期化 (Initiate Multipart Upload)、パートのアップロード×パートの数分 (Upload Part)、アップロード完了通知 (Complete Multipart Upload)の3つのリクエストを行う必要があり、アップロード完了通知を行って初めてS3のオブジェクトとして表示されます。

マルチパートアップロードに失敗した場合は、中止の通知 (Abort Multipart Upload) を行う必要があり、例えば、CLIを強制終了した場合等で適切に中止が行えなかった場合、
**アップロード途中のパートはS3側に残り続け、ストレージ費用が発生**します。

これについては、`aws s3api list-multipart-uploads`で確認できるので、明らかにゴミの場合は、`abort-multipart-upload` で削除しましょう。

```
aws s3api list-multipart-uploads --bucket <bucket_name> --region <region>
```

* [list-multipart-uploads](http://docs.aws.amazon.com/cli/latest/reference/s3api/list-multipart-uploads.html)
* [abort-multipart-upload](http://docs.aws.amazon.com/cli/latest/reference/s3api/abort-multipart-upload.html)

ライフサイクルルールで一定期間経過したマルチパートのパートを削除することができるので、今はこちらがお手軽です。

- [S3 バケットのライフサイクルポリシーを作成する方法 - Amazon Simple Storage Service](http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/user-guide/create-lifecycle.html)

# See Also

* [マルチパートアップロードの概要](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/mpuoverview.html)