aws-cliはs3転送の帯域制御をどのように実現しているのか

こんにちは。CTOの馬場です。

できるようになった、というのは見たものの、 具体的にどのように実現しているのか気になったので調べてみました。

こういうの、気になりません?わたしは気になります。

最近はコードの追い方の紹介をあまり見ないので、探し方を含めて紹介します。

なお30代後半以降の方にはお馴染みの、 find ... | xargs grep を使っていますが、 GitHubの検索機能でも代替可能です。

5秒でわかる結論

  • LeakyBucketです
  • aws-cliではなくbotoで実装されています

コードの追い方

ここからは地道に追ってみます。 読むだけだと何がなんだか...だと思うので、 操作したりリンクに飛んだりしながら試してみてください。

※jediやVSCodeで定義にジャンプできる環境がある場合はインストールしてジャンプしていけばもっと楽に追えると思います

下準備

まずはawscliのソースコードを落としてきます。

❯❯ ~/Documents/project/github.com/aws
❯ git clone git@github.com:aws/aws-cli.git
...
❯❯ ~/Documents/project/github.com/aws
❯ cd aws-cli
❯❯ (git:develop) ~/Documents/project/github.com/aws/aws-cli
❯ git checkout 1.14.39
...

とっかかり

設定項目が s3.max_bandwidth なので、 aws-cliのリポジトリで max_bandwidth を探します。

❯❯ (git:1.14.39) ~/Documents/project/github.com/aws/aws-cli
❯ find awscli -type f -name "*.py" | xargs grep -Hnw max_bandwidth
awscli/customizations/s3/transferconfig.py:25:    'max_bandwidth': None
awscli/customizations/s3/transferconfig.py:37:                         'max_bandwidth']
awscli/customizations/s3/transferconfig.py:39:    HUMAN_READABLE_RATES = ['max_bandwidth']
awscli/customizations/s3/transferconfig.py:112:        'max_bandwidth': 'max_bandwidth',

create_transfer_config_from_runtime_config 内で TransferConfig を生成する際に利用されているようです。

呼び出し元を探す

この create_transfer_config_from_runtime_config を呼んでいるのはどこでしょう?

❯❯ (git:1.14.39) ~/Documents/project/github.com/aws/aws-cli
❯ find awscli -type f -name "*.py" | xargs grep -Hnw create_transfer_config_from_runtime_config
awscli/customizations/s3/s3handler.py:22:    create_transfer_config_from_runtime_config
awscli/customizations/s3/s3handler.py:83:        transfer_config = create_transfer_config_from_runtime_config(
awscli/customizations/s3/transferconfig.py:97:def create_transfer_config_from_runtime_config(runtime_config):

transferconfig.py は先程のものなので、 s3handler.py があたりです。

ここでは transfer_configを生成しているようです。

この生成された transfer_configTransferManager で利用されます。

定義元を探す

TransferManager とは何でしょう? from s3transfer.manager import TransferManager を見ると s3transfer 配下です。

awscliではなく外部ライブラリのようです。

外部ライブラリを探す

依存している外部パッケージはsetup.pyに記載しておくことでインストール時にpipにて解決されます。 setup.py を見てみましょう。

s3transfer というそのままの名前のパッケージがありました。

PyPIを探す

外部パッケージはPyPIにあるので、そこでs3transferを探します。

https://pypi.python.org/pypi/s3transfer/

Home Page: https://github.com/boto/s3transfer

https://github.com/boto/s3transfer にコードがあるようです。

外部ライブラリの定義元を探す

boto/s3transferのリポジトリを見てみましょう。

❯❯ ~/Documents/project/github.com/boto
❯ git clone git@github.com:boto/s3transfer.git
...
❯❯ ~/Documents/project/github.com/boto
❯ cd s3transfer
❯❯ (git:develop) ~/Documents/project/github.com/boto/s3transfer
❯ git checkout 0.1.13
...
❯❯ (git:0.1.13) ~/Documents/project/github.com/boto/s3transfer
❯ grep -n TransferManager s3transfer/manager.py
69:            processing a call to a TransferManager method. Processing a
84:            TransferManager method calls that can be queued at a time. A value
156:class TransferManager(object):
535:        """Shutdown the TransferManager

TransferManagerの定義がありました。

処理を追う

コンストラクタの中でmax_bandwidthを含むtransfer_config(だったもの)が self._config として保持されています。

コンストラクタを下に読み進めると、なんと max_bandwidth が利用されています。

leaky_bucket = LeakyBucket(self._config.max_bandwidth)
self._bandwidth_limiter = BandwidthLimiter(leaky_bucket)

これっぽい

帯域などの制限でよくある leaky bucket (水漏れバケツ) 方式のようですね。 めでたしめでたし。

さらに深追いするなら

あとはコードを読んで定義にジャンプしていけば大丈夫です。 このような流れで追っていく形になると思います。

  1. https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L92-L94
  2. https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L138-L156
  3. https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L158-L173
  4. https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L237-L264

さらにさらに深追いするにはこのあたりを読むことになると思います。

  1. https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L288
  2. https://github.com/boto/s3transfer/blob/0.1.13/s3transfer/bandwidth.py#L341

まとめ

単にユーザとして使ってるだけだと仕組みも何もわからなくて不安ですよね? せっかくコードが公開されているので、活用してきちんと自分の掌に収めていきましょう。

株式会社ハートビーツのインフラエンジニアから、ちょっとした情報をお届けします。