跳到主要内容

大量小文件传输实测:rsync、tar、SFTP、TCP 与 QUIC 对比

从德国到美国,在 141 ms 往返延迟下传输 65,536 个小文件。实测 rsync、tar、Btrfs 快照、完整磁盘镜像,以及 TCP/QUIC 与不同拥塞控制设置。

WarpSend 工程团队 内容核查 Charlie 3 分钟阅读

我想知道,一个装满小文件的目录,复制起来到底慢在哪里。我测试了 rsync、流式 tar、快照复制和完整磁盘镜像复制,再用一个简单的 Rust 传输程序调整传输设置。

数据是 65,536 个文件,每个 4,096 bytes,合计 268.4 MB。从德国传到美国,往返延迟约 141 ms RTT。两台 VM 都有 4 个 vCPU 和 8 GB 内存。所有方法都使用 Btrfs loop 卷,预先读取源数据,目标端从空目录开始,不启用压缩。每种设置按打乱的顺序测试五次。速度按有效文件字节数,除以接收端文件可用所需的时间计算;之后才做 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 以数据流的形式传输文件数据和文件系统操作。原始镜像复制则搬运整个 2.15 GB 镜像,连未使用空间也一起传,只为交付 268.4 MB 的文件。增量快照和变更块复制需要用数据更新的场景测试;这里只测了完整复制。

另一批测试使用 Rust 程序,在 Linux TCP/TLS/yamux 和 Quinn QUIC 之间共用文件 I/O 代码。一种模式允许最多 4,096 条文件流同时进行,另一种把记录打包成一条连续的数据流。两者都能跨越文件边界持续传输,不必等每个文件完成。

单条连接的传输速度(MB/s):

文件处理方式TCP + CUBICTCP + BBRQUIC + CUBICQUIC + BBR
跨文件流水线16.9920.046.5828.41
流式打包20.9019.096.9129.26

五次测试的中位数。

跨文件流水线与流式打包,在 TCP 或 QUIC 搭配 CUBIC 或 BBR 时的传输速度对比,单位为 MB/s。 打开原尺寸图表
圆点保留每一次观测,包括较慢的结果。

把 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。这也同时增加了读写的并发度。大文件仍然快得多:

小文件与大文件使用一条或八条连接时的传输速度,单位为 MB/s。 打开原尺寸图表
总量同样是 268.4 MB。大文件对照组使用一个文件搭配一条连接,或八个等大的文件搭配八条连接。

较早的工具测试,曾因另一个工作负载的 SSH 失败而中断,之后继续完成;80 次 Rust 测试则全程没有中断。这两台共享 VM 出现过 UDP 缓冲区错误,以及偶发的 CPU steal,也就是虚拟机等待宿主机分配 CPU 的时间。两批测试的实现和计时范围也不同,不能把它们当作只改变传输协议的对比。设置与审计细节(英文)。

我会先检查,发送端是否会在文件边界停下来等待,再测试拥塞控制器。Tar、rsync 的流水线和自定义跨文件流水线,都在解决第一个问题。在这次 Quinn 的传输路径上,跨文件连续传输加上 BBR 的效果很好。TCP 没有得到相同的 BBR 收益。只看协议名称或复制所在的层级,无法知道这两件事是否做好了。如需逐步诊断自己的文件夹,请见大量小文件传输为什么很慢?原因与加速方法。

我参与 WarpSend 的开发,所以很在意这些细节。这个实验没有使用 WarpSend 的产品代码。

工具测试结果(英文) · 全部 80 条 Rust 观测(英文) · 测试程序与方法(英文)