Chapter 05

ファイル転送してみる / S3 Transfers

Akane
Akane
2021.02.21に更新

Cloudianは、AWSのS3完全互換のAPIを持ったオブジェクトストレージです。

今回は、Python(boto3)で、オブジェクトストレージのファイル転送をしてみたいと思います。

S3 Transfers によるファイル転送処理 (ファイルのアップロード/ダウンロード)

boto3 には、より簡易に/より効率的にアップロード/ダウンロード操作を行うことができる S3
Transfers というモジュールが用意されています。

S3 Transfers は、以下のような機能を提供しています。

  • 指定したファイルサイズを上回った際に、自動的にマルチパート転送に切り替わります。
  • 並列処理でファイルのアップロード/ダウンロードを実行します。
  • ネットワークの最大帯域幅に応じて、ファイルを転送します。
  • 転送状況をモニタリングするために、転送の進捗状況をコールバックできます。
  • ファイルのアップロード時に、リトライを実行します。

S3 Transfers のパラメータのデフォルト値には最適な値が設定されていますが、以下のパラメータ設定を変更することもできます。

  • マルチパート閾値サイズ
  • 並行ダウンロード処理の最大数
  • 使用するネットワーク最大帯域幅
  • ソケット・タイムアウト値
  • リトライ回数

S3 Transfers のパラメータを変更するには、変更対象のパラメータの設定値を引数に指定して、
TransferConfig オブジェクトを作成します(事前に "boto3.s3.transfer.TransferConfig" をインポートする必要があります)

test.py
from boto3.s3.transfer import S3Transfer
from boto3.s3.transfer import TransferConfig

config = TransferConfig(
    multipart_threshold = 8 * 1024 * 1024,
    max_concurrency = 10,
    multipart_chunksize = 8388608,
    num_download_attempts = 10,
    max_io_queue = 100
)

transfer = S3Transfer(client, config)

1. S3Transfer オブジェクトの作成

S3 Transfers の機能を利用するためには、まず S3Transfer オブジェクトを作成します。
事前に、boto3.s3.transfer.S3Transfer をインポートしておく必要があります。本書の例では、既に S3Transfer はインポート済みの状態になっています。

S3Transfer()の引数に、既に作成済みの S3Client オブジェクトを渡して S3Transfer オブジェクトを作成します。S3Client オブジェクトのみを引数として渡し S3 Transfers オブジェクトを作成した場合には、S3 Transfers のパラメータは全てデフォルト値が使用されます。

transfer = S3Transfer(client)

2. ファイルのアップロード / S3Transfer.upload_file()

S3 Transfers を使用して Cloudian にファイルをアップロードするには、 upload_file()を使用します。
extra_args 引数を設定して upload_file()を呼び出すこと により、アップロード時にオブジェクト(ファイル)の ACL を設定したり、メタデータを付加したり、 暗号化を行ったりできます。

シンプルなファイルのアップロード

以下の例では、ローカルにあるファイル「10mb.dat」を、 Cloudian のバケット「pythonbucket1」にキー「10mb.dat」を設定してアップロードして います。

transfer.upload_file('fileup/10mb.dat', 'pythonbucket1', '10mb.dat')

下図は、 upload_file()の使用例で Cloudian にアップロードしたファイルを Cloudant Mamagement Console(以下CMC) の オブジェクト画面から参照したものです。

3-3-2.png

アップロード時に ACL、メタデータ、暗号化を指定

以下の例では、ローカルにあるファイル「10mb.dat」を、Cloudian のバケット「pythonbucket1」にキー「10mb.dat」を指定し、extra_args を設定してオブジェク トの ACL には「public-read」、3 つのメタデータを付加して「AES256」でサーバーサイド暗号化するように指定してアップロードしています。

transfer.upload_file(
    'fileup/10mb.dat', 'pythonbucket1', '10mb.dat',
    extra_args={
                'ACL': 'public-read',
                'Metadata': {
                    'Purpose': 'boto3 demo',
                    'Engineer': 'yamahiro',
                    'Company': 'Networld'
               },
               'ServerSideEncryption': 'AES256'
    }
)

upload_file()の extra_args パラメータ「ServerSideEncryption」を使用し、AES256 で サーバーサイド暗号化を行うように設定したので、ファイル名の先頭に「🔒」マークが表示され、このファイルが暗号化されていることが分かります。

3-3-3.png

また、下図のようにこのファイルのプロパティを開いてみると、extra_args パラメータの ACL で設定したように、このファイルのアクセス権に「パブリック:読み出し可能('ACL': 'public-read')」にチェックが入っていることが分かります。

3-3-4.png

3. ファイルのダウンロード / S3Transfer.download_file()

S3 Transfers を使用して Cloudian からファイルをダウンロードするには、 download_file()を使用します。extra_args 引数を設定して download_file()を呼び 出すことにより、ダウンロード時にオブジェクトのバージョン ID を指定したりすることができます。

以下の例では、バケット「pythonbucket1」に保存されているキー「10mb.dat」の最新 バージョンのオブジェクトをダウンロードしています。

バケット「pythonbucket1」のバージョニング機能が有効にされていた場合、この例ではバー ジョン ID を指定していないので“最新バージョンのオブジェクト”がダウンロードされます(バージョニ ング機能については、後述します)。

transfer.download_file('pythonbucket1', '10mb.dat', 'filelocal/10mb-local.dat')

バージョニング機能が有効な場合

以下の例では、バージョニング機能が有効化されているバケット「pythonbucket1ver」に保存されているキー「10mb.dat」の、バージョン ID が「fe14c26e-1662-4f8f-a754-06bdfcde1d5e」のオブジェクトをダウンロードしています。

transfer.download_file(
    'pythonbucket1ver', '10mb.dat', 'filelocal/10mb-local.dat',
    extra_args={'VersionId': 'fe14c26e-1662-4f8f-a754-06bdfcde1d5e'}
)

S3 Transfers を使用したファイルのアップロード/ダウンロード時には、マルチパート閾値サイ ズ(multipart_threshold)が設定されており、そのデフォルト値は「8,388,608 bytes(約 8MB)」になっています。

アップロード/ダウンロード対象のファイルサイズが 8MB よりも大きい場合、S3 Transfers は 自動的に複数のパーツにファイルを分割して同時並行で処理を実行します。

下図は大きなサイズのファイルを S3 Transfers でアップロードを行っているときの、CMC オブジェクト画面のスクリーンショットです。8MB よりも大きなファイルは、自動的にマルチパートアップロードが実行されていることが分かります。

3-3-5.png

※補足: get_object() を使用したファイルのダウンロード

S3Transfers オブジェクトの download_file()を使用したファイルのダウンロード以外に、低レベル API に対応する get_object() を使用してファイルのダウンロードを行うこともできます。

with open('filelocal/10mb-local.dat', 'wb') as f:
    f.write(client.get_object(
            Bucket='pythonbucket1ver',
            Key='10mb.dat',
            VersionId='fe14c26e-1662-4f8f-a754-06bdfcde1d5e'
        )['Body'].read()
    )

ただしこの場合、上記サンプルコードのように、S3Transfers オブジェクトを使用した方法よりも若干、 コードが複雑になります。同じ操作を実行するために複数の方法があることがありますので、適材適所で どの方法を使用するか決める必要があります。

まとめ

Python(boto3)で、ファイル転送(アップロード/ダウンロード)をしてみました。