为什么 scp 这么慢以及如何使它更快?

lau*_*ent 88 scp time batch-jobs

我正在尝试复制一批文件,scp但速度很慢。这是一个包含 10 个文件的示例:

$ time scp cap_* user@host:~/dir
cap_20151023T113018_704979707.png    100%  413KB 413.2KB/s   00:00    
cap_20151023T113019_999990226.png    100%  413KB 412.6KB/s   00:00    
cap_20151023T113020_649251955.png    100%  417KB 416.8KB/s   00:00    
cap_20151023T113021_284028464.png    100%  417KB 416.8KB/s   00:00    
cap_20151023T113021_927950468.png    100%  413KB 413.0KB/s   00:00    
cap_20151023T113022_567641507.png    100%  413KB 413.1KB/s   00:00    
cap_20151023T113023_203534753.png    100%  414KB 413.5KB/s   00:00    
cap_20151023T113023_855350640.png    100%  412KB 411.7KB/s   00:00    
cap_20151023T113024_496387641.png    100%  412KB 412.3KB/s   00:00    
cap_20151023T113025_138012848.png    100%  414KB 413.8KB/s   00:00    
cap_20151023T113025_778042791.png    100%  413KB 413.4KB/s   00:00    

real    0m43.932s
user    0m0.074s
sys 0m0.030s
Run Code Online (Sandbox Code Playgroud)

奇怪的是,传输速率大约为 413KB/s,文件大小大约为 413KB,所以它真的应该每秒传输一个文件,但是每个文件大约需要 4.3 秒。

知道这种开销从何而来,有没有办法让它更快?

roa*_*ima 86

您可以使用rsync(over ssh),它使用单个连接来传输所有源文件。

rsync -avP cap_* user@host:dir
Run Code Online (Sandbox Code Playgroud)

如果您没有rsync(为什么没有!?),您可以像这样使用tarwith ssh,这样可以避免创建临时文件(这两个替代方案是等效的):

tar czf - cap_* | ssh user@host tar xvzfC - dir
tar cf - cap_* | gzip | ssh user@host 'cd dir && gzip -d | tar xvf -'
Run Code Online (Sandbox Code Playgroud)

rsync所有其他条件相同的情况下,这是首选,因为它可以在发生中断时重新启动。

  • 您是说单个 `scp` 调用不会使用单个连接来传输所有文件吗? (10认同)
  • 这太快了,太疯狂了……非常感谢 (3认同)
  • 在 tarpipe 的情况下,每一侧都不需要 `f -`,因为默认情况下 tar 输出到 stdout/stdin 或从 stdout/stdin 读取。所以`tar cz cap_* | ssh user@host tar xvzC dir` 就可以了。 (2认同)
  • @tremby不一定。`tar` 可以使用不同的默认值进行编译(如果您使用的是 GNU tar,请参阅 `tar --show-defaults` ,否则请参阅 `/etc/default/tar` ,并且在这两种情况下都不要忘记 `TAPE ` 环境变量) (2认同)

小智 23

@wurtel 的评论可能是正确的:建立每个连接都有很多开销。如果您能解决这个问题,您将获得更快的传输(如果不能,请使用@roaima 的rsync解决方法)。我做了一个实验,将类似大小的文件(head -c 417K /dev/urandom > foo.1并制作了该文件的一些副本)传输到需要一段时间才能连接的主机(HOST4)和响应非常快的主机(HOST1):

$ time ssh $HOST1 echo


real    0m0.146s
user    0m0.016s
sys     0m0.008s
$ time scp * $HOST1:
foo.1                                         100%  417KB 417.0KB/s   00:00    
foo.2                                         100%  417KB 417.0KB/s   00:00    
foo.3                                         100%  417KB 417.0KB/s   00:00    
foo.4                                         100%  417KB 417.0KB/s   00:00    
foo.5                                         100%  417KB 417.0KB/s   00:00    

real    0m0.337s
user    0m0.032s
sys     0m0.016s
$ time ssh $HOST4 echo


real    0m1.369s
user    0m0.020s
sys     0m0.016s
$ time scp * $HOST4:
foo.1                                         100%  417KB 417.0KB/s   00:00    
foo.2                                         100%  417KB 417.0KB/s   00:00    
foo.3                                         100%  417KB 417.0KB/s   00:00    
foo.4                                         100%  417KB 417.0KB/s   00:00    
foo.5                                         100%  417KB 417.0KB/s   00:00    

real    0m6.489s
user    0m0.052s
sys     0m0.020s
$ 
Run Code Online (Sandbox Code Playgroud)

  • 所以你的假设是它为每个文件建立一次新连接? (2认同)

dr_*_*dr_ 16

转让的谈判需要时间。通常,对nb字节文件的操作比对n * b字节的单个文件的单个操作花费的时间要长得多。这也适用于磁盘 I/O。

如果仔细观察,您会发现在这种情况下的传输速率是size_of_the_file /secs。

要更有效地传输文件,请将它们与 捆绑在一起tar,然后传输 tarball:

tar cvf myarchive.tar cap_20151023T*.png

或者,如果您还想压缩存档,

tar cvzf myarchive.tar.gz myfile*

是否压缩取决于文件内容,例如。如果它们是 JPEG 或 PNG,则压缩不会产生任何效果。

  • @Dave 在我的例子中(现代 7000 rpm HD 上的数据,高端 CPU,非常快的网络,根本不吹牛),没有压缩的 tar 纯粹是 IO 限制,但使用 `-z` 是 CPU 限制,而且速度要慢得多。gzip 将始终尝试压缩,因此速度变慢;毕竟,在您尝试压缩之前,您无法判断一串字节是否可压缩。在我的设置中,即使在传输纯文本文件时,与最轻的压缩相比,没有压缩的 rsync 也是最快的 2-3 倍。当然,YMMV。 (4认同)

Fre*_*eit 7

我使用了这里描述的技术(存档),它使用并行 gzip 和 netcat 来快速压缩和复制数据。

归结为:

# SOURCE: 
> tar -cf - /u02/databases/mydb/data_file-1.dbf | pigz | nc -l 8888

# TARGET:
> nc <source host> 8888 | pigz -d | tar xf - -C /
Run Code Online (Sandbox Code Playgroud)

这使用 tar 来收集一个或多个文件。然后使用pigz获取多个cpu线程压缩发送文件,网络传输使用netcat。在接收端,netcat 侦听然后解压缩(并行)和解压缩。

  • `nc` 未加密。添加一些`ssh -D`魔法吗? (5认同)

小智 7

scp 比它应该慢的另一个原因,尤其是在高带宽网络上,是它有静态定义的内部流量控制缓冲区,最终成为网络性能瓶颈。

HPN-SSH是 OpenSSH 的修补版本,它增加了这些缓冲区的大小。它对scp 传输速度产生了巨大的影响(请参阅网站上的图表,但我也是根据个人经验发言的)。当然,要获得这些好处,您需要在所有主机上安装 HPN-SSH,但如果您经常需要传输大文件,这非常值得。


bvj*_*bvj 5

刚刚通过scp. 获得 ~250KB/s。在目标防火墙上禁用 UDP 洪水保护 (FP) 后,传输速率增加到 6.5MB/s。当重新打开 FP 时,速率回落到 ~250KB/s。

发送方:cygwin,接收方:Fedora 20,防火墙 Sophos UTM。

SSH 使用 UDP 做什么?@ superuser.com --它不是直接来自我阅读的内容。

在查看防火墙日志时,泛洪检测发生在公共 IP 地址上的源和目标端口 4500 上,而不是私有站点到站点内部 VPN 地址。所以看起来我的问题可能是 NAT Traversal 情况,其中scpTCP 数据最终被加密并封装在 ESP 和 UDP 数据包中,因此受到 FP 的影响。为了scp从等式中删除,我在 VPN 上运行了 Windows 文件复制操作,并注意到scp启用和不启用 FP 的性能相似。还iperf通过 TCP进行了测试,注意到使用 FP 时为 2Mbits/sec,不使用时为 55Mbits/sec。

NAT-T 如何与 IPSec 协同工作?@cisco.com