最近在迁移网站数据的时候遇到了一个特别头疼的问题:几万个零碎的小文件,原本以为直接 scp 或者 cp 过去就完事了,结果速度慢得像蜗牛爬,甚至把 CPU 都跑满了。这让我不得不重新思考:当面对海量小文件时,到底是直接复制快,还是先打包再传输更划算?

为什么直接复制会“翻车”?

很多时候我们直觉上觉得,直接复制文件最简单,不需要中间步骤。但在服务器运维的场景下,这个直觉往往是错的。

问题的核心在于 IO 开销

每一次文件的读写操作,系统都需要进行元数据的交互(创建索引、更新权限、修改时间戳等)。如果你有 10 万个小文件,系统就要处理 10 万次这样的元数据操作。相比之下,复制一个 1GB 的大文件,系统只需要处理一次元数据操作。小文件传输不仅占用了大量的磁盘 IOPS(每秒读写次数),还会造成大量的上下文切换,CPU 的负载也会因此飙升。

文件系统元数据操作示意图

文件系统元数据操作示意图

如果是通过公网传输,网络延迟还会进一步放大这个问题。每一个小文件建立传输连接的握手时间,累积起来甚至比传输数据本身的时间还要长。

工具大比拼:rsync vs tar

为了找到最优解,我对比了两套最常见的方案。这里不谈复杂的理论,直接说实战结论。

方案一:rsync(增量同步的王者)

rsync 是很多人首选的工具,它的优势在于增量同步。如果文件已经存在且内容没有变化,它就不会重复传输,这对于日常备份来说非常节省带宽。

tar 管道流式传输原理图

tar 通过管道与 SSH 结合的流式传输原理

但是,在处理海量小文件时,rsync 的性能取决于你的算法参数和文件系统。默认情况下,它需要建立文件列表并进行校验,这本身就需要消耗大量的时间和内存。如果仅仅是第一次全量迁移,它并不一定是速度最快的。

方案二:tar(打包流式传输)

如果你是在做第一次全量备份,tar + ssh 几乎总是碾压 rsync 的。

它的原理非常简单:把文件先打包(并不需要真正在硬盘上生成一个 tar 包),然后通过管道直接流式传输给另一端的 tar 命令进行解压。这种方式将无数个小文件的 IO 操作合并为了一个大文件的连续流操作,极大地减少了元数据的开销。

实战解决方案与代码

既然知道了问题的症结,那具体该怎么操作呢?别担心,我已经整理好了现成的命令,直接拿来用就行。

1. 首选方案:利用 tar 流式传输(推荐)

这是速度最快的方法,适合大规模数据的初次迁移。

在源服务器执行:

tar cf - /path/to/source | ssh user@remote_ip "tar xf - -C /path/to/destination"

如果你想看到进度条(需要安装 pv 工具),可以用这个增强版:

tar cf - /path/to/source | pv | ssh user@remote_ip "tar xf - -C /path/to/destination"

注意: 这里的 -C 参数指定了解压的目标目录,一定要确保远程目录已经存在且有写入权限。

2. 带压缩的流式传输(带宽吃紧时用)

如果你的服务器带宽很贵或者很慢,CPU 性能又比较强,可以加上压缩参数(z 表示 gzip)。

tar czf - /path/to/source | ssh user@remote_ip "tar xzf - -C /path/to/destination"

不过要注意,如果是 JPG、PNG 或者 MP4 这种已经压缩过的文件,再次压缩不仅浪费时间,效果也不明显,甚至还可能适得其反(变大)。如果是纯文本日志或代码,压缩率会非常高,值得使用。

3. 既想要速度又想要增量?(进阶组合)

如果你是日常备份,不想每次都全量传输,但又要克服 rsync 慢的问题,可以尝试先用 tar 打包传输,然后在同机器(或同机房内网低延迟环境下)再使用 rsync 进行校验和增量同步。

或者,你可以考虑使用 rsync--whole-file (-W) 参数,这会强制 rsync 跳过 delta 算法的差异比对,直接传输整个文件。在网络良好但本地 IO 是瓶颈的情况下,这反而能提升速度。

rsync -avzW /path/to/source/ user@remote_ip:/path/to/destination/

还有一个冷门的“作弊”技巧

有些小文件其实是可以合并不必分开存的。比如网站的图片,如果数量巨大但又访问平淡,可以考虑将它们存入数据库(BLOB)或者使用对象存储(S3/OSS),彻底抛弃传统的文件系统存储,这样不仅备份方便,访问性能在特定场景下也会更好。

总结

别再傻傻地用 scp -r 去拷几十万个文件夹了。

  • 第一次全量迁移:请务必使用 tar | ssh 流式传输。
  • 日常增量备份:使用 rsync,但在小文件极多的情况下,考虑先打包再同步,或者调优参数。
  • 带宽受限:加上 gzip 压缩,但记得先看看文件是不是已经是压缩格式。

希望这篇笔记能帮你在服务器运维中少踩几个坑,省下更多的时间去摸鱼!如果你有更高效的骚操作,欢迎在评论区交流。

标签: none

AI Skills Smart Station on Nick Launches

评论已关闭