小さなファイル転送のベンチマーク:rsync、tar、SFTP、TCP、QUIC を比較
ドイツから米国へ、RTT 141 ms の回線で 65,536 個の小さなファイルを転送。rsync、tar、Btrfs スナップショット、ディスクイメージ、TCP/QUIC と輻輳制御を実測しました。
小さなファイルが詰まったディレクトリは、何が原因でコピーに時間がかかるのか。rsync、tar のストリーミング転送、スナップショット複製、ディスクイメージ全体のコピーを試し、続いて小さな Rust 製転送プログラムで通信設定を変えてみました。
データは 4,096 bytes のファイル 65,536 個、合計 268.4 MB です。ドイツから米国へ転送し、往復遅延は約 141 ms RTT。両方の VM は 4 vCPU、メモリ 8 GB でした。すべての方法で Btrfs のループバックボリュームを使い、転送元を事前に読み込み、転送先は空の状態から開始。圧縮は無効にしました。各設定を、順序をシャッフルして五回ずつ測定しています。速度は実際のファイルデータ量を、受信先でファイルが利用可能になるまでの時間で割った値です。その後に sync と SHA-256 検証を行い、完了したコピーはすべて検証に合格しました。
まず既存ツールを、データ接続一本で比較しました。完了した転送の速度は五回の中央値です。
| 方法 | 転送速度(MB/s) |
|---|---|
| OpenSSH SFTP | <0.299* |
rsync(--whole-file) | 10.65 |
| tar ストリームを SSH で転送 | 10.05 |
| Btrfs フルスナップショット送信 | 10.84 |
| ディスクイメージ全体のコピー | 1.71† |
SFTP は五回とも 15 分の制限時間に達しました。数値は全データの転送完了速度の上限です。†イメージのコピーでは、実際のファイルデータ量の八倍を送っています。全測定結果と計時の詳細(英語)。
この RTT でファイルごとに一往復余計に待つと、合計で 2.6 時間増える計算になります。OpenSSH 9.6 の再帰 SFTP クライアントはファイルを一つずつ処理し、パイプライン処理は各ファイルの内部で行います。Tar はアーカイブのストリームを SSH 経由で別の tar プロセスへ送り、受信側は届いた分から展開します。Rsync はもともとファイルをまたぐパイプライン処理を使います。まとめて送ることもパイプライン化も、前のファイルが終わる前に次のファイルを流せる点は同じです。ただし、このツール比較にはほかの実装差も含まれます。
Btrfs のフル send は、ファイルデータとファイルシステム操作をストリームとして送ります。一方、イメージ全体のコピーでは、268.4 MB のファイルを届けるために、未使用領域を含む 2.15 GB 全体を転送しました。増分スナップショットや変更ブロックだけの複製を評価するには、データ更新を伴うテストが必要です。今回は全量コピーだけを測りました。
別の測定では、Rust プログラムで Linux TCP/TLS/yamux と Quinn QUIC のファイル I/O コードを共通化しました。一方のモードは最大 4,096 本のファイルストリームを同時に処理し、もう一方はレコードを一本の連続ストリームにまとめます。どちらもファイル単位の完了を待たず、ファイルをまたいで送り続けます。
接続一本での転送速度(MB/s):
| ファイルの扱い | TCP + CUBIC | TCP + BBR | QUIC + CUBIC | QUIC + BBR |
|---|---|---|---|---|
| ファイル間のパイプライン処理 | 16.99 | 20.04 | 6.58 | 28.41 |
| 一本のストリームにまとめる | 20.90 | 19.09 | 6.91 | 29.26 |
五回の測定の中央値。
グラフを原寸で開くCUBIC から BBR に変えると、まとめて送る QUIC は 6.91 から 29.26 MB/s に上がりました。同じ変更で TCP は 20.90 から 19.09 MB/s になっています。輻輳制御を変えると TCP と QUIC の順位が逆転しました。ただし、Linux と Quinn の制御アルゴリズムは別々の実装です。
独立した BBR 接続を八本使うと、小ファイルをまとめた転送は TCP で 38.04 MB/s、QUIC で 36.83 MB/s になりました。この変更は読み書きの並列度も増やします。それでも、大きなファイルの方がずっと高速でした。
グラフを原寸で開く先のツール測定には、別のワークロードで SSH 障害が起きた後に再開した分が含まれます。Rust の 80 回は中断なく実行されました。この共有 VM では UDP バッファエラーと、一時的な CPU steal、つまり VM がホストから CPU を割り当てられるのを待つ時間が観測されています。二つの測定群は実装も計時範囲も異なるため、通信プロトコルだけを変えた比較にはできません。設定と監査の詳細(英語)。
まず確認したいのは、ファイルの切り替わりで送信が止まっていないか。その次に輻輳制御を試します。Tar、rsync のパイプライン、自作のファイル間パイプラインは、いずれも最初の問題に対処します。今回の Quinn の転送経路では、ファイルをまたぐ連続転送と BBR がよく効きました。TCP では BBR による同じ効果は得られていません。プロトコル名や複製を行う層だけでは、この二点がうまく機能しているかは分かりません。自分のフォルダーを順を追って診断する方法は、小さいファイルの転送が遅い理由と高速化する方法で説明しています。
私は WarpSend の開発に関わっているので、こうした細部が気になります。この実験では WarpSend の製品コードは使っていません。