使磁盘/磁盘复制变慢


28

有没有一种方法可以减慢Linux上的复制过程?

我有一个大文件,例如10GB,我想将其复制到另一个目录,但是我不想全速复制。假设我想以1mb / s的速度复制它,而不是更快。我想使用标准的Linux cp命令。

这可能吗?(如果是,如何?)

编辑:因此,我将为我要实现的内容添加更多上下文。

通过USB将大文件复制到pendrive,usb磁盘等时,我在ArchLinux系统上遇到问题。填满USB缓冲区高速缓存后,我的系统停止响应(即使鼠标停止;它也只是偶尔移动)。复制操作仍在进行中,但是占用了100%的资源。复制操作完成后,一切都会恢复正常-一切都再次完美响应。

我不知道这可能是硬件错误,但我确实知道我有两台机器都遇到此问题(两者都在ArchLinux上,一台是台式机,另一台是笔记本电脑)。

对此最简单,最快的“解决方案”(我同意这不是“真正的”解决方案,只是一个丑陋的“ hack”)将通过以USB驱动器的平均写入速度复制文件来防止该缓冲区被填满,例如对我来说就足够了。


7
如果您试图限制磁盘到磁盘的复制速度以“好”于系统中其他受I / O约束的进程,则最好利用内核调整I / O调度的能力。代替。具体地说,ionice可用于确保磁盘到磁盘复制过程的计划I / O优先级低于常规过程。
史蒂文星期一

3
这是一个经典的XY问题。相反,您应该问一下,当您将文件复制到USB设备时,为什么桌面无响应。
迈克尔·汉普顿

4
如今,Linux实际上具有可笑的大I / O缓冲区。RAM的大小增长速度快于大容量存储速度。也许您可以使用dd(1)执行复制并进行同步,以使它实际上可以定期同步而不是被缓冲?管道查看器(pv)具有速率限制选项。有点像cat file | pv -L 3k > outfile。但是,两者都与使用cp(1)相同。
ptman 2014年

@MichaelHampton,在ArchLinux论坛上有几个未解决的主题,因此我想我将尝试以另一种方式来处理它,以使其正常工作。
安东尼

@antonone但是Unix.SE不是ArchLinux的论坛。这里有人可以解决。
Izkata 2014年

Answers:


23

您可以使用pv -qL(或cstream -t提供类似功能)限制管道

tar -cf - . | pv -q -L 8192 | tar -C /your/usb -xvf -

-q 删除stderr进度报告。

-L限制是以字节为单位。

有关--rate-limit/-L来自的标志的更多信息man pv

-L RATE, --rate-limit RATE

    Limit the transfer to a maximum of RATE bytes per second.
    A suffix of "k", "m", "g", or "t" can be added to denote
    kilobytes (*1024), megabytes, and so on.

最初指出的答案throttle是该项目,但该项目不再可用,因此已退出某些软件包系统。


如果cp不能放慢脚步,那么我猜唯一的选择是使用自定义命令。
2014年


看起来更复杂,但对我来说更有用。需要测试文件锁定机制,并需要将复制速度减慢到某些字节/秒,这对于rsync似乎是不可能的。虐待尝试一下,然后通过节流管“
抓取

伤心地说,但该项目是死bugs.debian.org/cgi-bin/bugreport.cgi?bug=426891
cljk

1
@cljk更新为pv。谢谢。
马特

23

取而代之的是,cp -a /foo /bar您还可以rsync根据需要使用和限制带宽。

rsync的手册中:

--bwlimit=KBPS

限制I / O带宽;每秒千字节

因此,actuall命令(也显示进度)如下所示:

rsync -av --bwlimit=100 --progress /foo /bar

这听起来像是复制我不想打的旧驱动器的好主意。
jeremyjjbrown 2015年

不适用于阅读/dev/zero/dev/random
-cdosborn

rsync -a --bwlimit=1500 /source /destination可以完美地以1.5 MB / s的速度复制巨型文件夹(这在避免服务器减速和不花费太多时间之间是一个很好的平衡)
lucaferrario

旁注:即使手册页可能会说您可以使用字母表示单位,例如20m,并非所有平台都支持,所以最好坚持使用千字节表示法。
Hubert Grzeskowiak

拯救了我的一天!cgroup cgexec -g ... cp /in /out并非一直都在工作(从终端工作了一段时间,从没有脚本开始),我也不知道为什么……
Aquarius Power

13

我认为您正在尝试不破坏其他活动。Linux的最新版本包括ionice允许您控制IO调度的版本。

除了允许各种优先级外,还有一个附加选项可将IO限制为磁盘空闲时的时间。该命令man ionice将显示文档。

尝试使用以下命令复制文件:

ionice -c 3 cp largefile /new/directory

如果两个目录位于同一设备上,则可能会发现链接文件符合您的要求。如果出于备份目的而复制,则不要使用此选项。 ln由于文件本身不会被复制,因此速度非常快。尝试:

ln largefile /new/directory

或者,如果您只想从其他设备上的目录访问它,请尝试:

ln -s largefile /new/directory

ionice在linux中运作良好吗?我读它只是“模仿”工作,没有真正的区别吗?+1链接
尼克

1
@Nick当我使用它时,它的表现符合预期。我应用ionice的过程大大减慢了速度,而其他需要I / O的过程则能够按预期执行。在其他进程有中等I / O负载的情况下,我能够通过按预期方式应用最大的“漂亮”来有效地暂停高I / O进程。一旦没有竞争性的I / O,离子化过程就会照常进行。
BillThor 2015年

当我将400MB的文件从一个HD复制到SSD时,最初的10s可以正常工作,然后突然我看到我的IO负载很高,不得不等待1分钟的机器冻结:/。我对cgroup写入io节流阀有同样的问题,有时它会工作,而另一些它根本不会工作。
水瓶座力量

7

如果ionice解决方案还不够(无论如何),并且您确实想将I / O限制为绝对值,则有几种可能性:

  1. 最简单的方法:ssh。它具有内置的带宽限制。您可以使用eg tar(而不是cp)或scp(如果足够好;我不知道它如何处理符号链接和硬链接)或rsync。这些命令可以通过管道传递数据ssh。如果tar您写入/dev/stdout(或-)并将其通过管道ssh传输到客户端,该客户端将tar在“远程”端执行另一个操作。

  2. 优雅但不适用于香草内核(AFAIK):设备映射器target ioband。当然,仅当您可以挂载源卷或目标卷时,此方法才起作用。

  3. 一些自写的乐趣:grep "^write_bytes: " /proc/$PID/io为您提供进程已写入的数据量。您可以编写一个脚本,该脚本cp在后台启动,休眠例如1/10秒,停止后台cp进程(kill -STOP $PID),检查已写入的数量(在这种情况下,读取并读取大约相同的值),计算多长时间cp必须暂停以使平均传输速率降低到预期值,然后休眠一段时间,然后唤醒cpkill -CONT $PID),依此类推。


是的,通常我只是使用lftp通过scp连接到本地主机,并从那里限制带宽。
2014年

5

您的问题可能不在于计算机本身,这可能很好。但是那个USB闪存过渡层具有自己的处理器,该处理器必须映射所有写操作,以补偿多达90%的故障闪存芯片的故障,谁知道呢?先泛洪它,然后泛滥缓冲区,然后泛洪整个总线,然后陷入困境,伙计-毕竟,这就是所有东西的所在。听起来可能违反直觉,但您真正需要的是阻止I / O-您需要让FTL设定速度,然后再跟上。

(关于黑客攻击FTL微控制器:http : //www.bunniestudios.com/blog/? p=3554 )

以上所有答案都应该起作用,所以这更像是“我也是”!最重要的是:我已经去过那里了,老兄。我用rsync的--bwlimit arg 解决了自己的问题(2.5mbs似乎是单次无错误运行的最佳途径-除此之外,我还会遇到写保护错误)。rsync特别适合我的目的,因为我正在使用整个文件系统-因此有很多文件-并且仅第二次运行rsync即可解决所有第一次运行的问题(当我感到不耐烦并尝试时,这是必需的超过2.5mbs)。

不过,我想对于单个文件而言,这还不太实际。在您的情况下,您可以通过管道将dd设置为raw-write-您可以用这种方式处理任何输入,但是一次只能处理一个目标文件(尽管单个文件可以是整个块设备)。

## OBTAIN OPTIMAL IO VALUE FOR TARGET HOST DEV ##
## IT'S IMPORTANT THAT YOUR "bs" VALUE IS A MULTIPLE ##
## OF YOUR TARGET DEV'S SECTOR SIZE (USUALLY 512b) ##
% bs=$(blockdev --getoptio /local/target/dev)

## START LISTENING; PIPE OUT ON INPUT ##
% nc -l -p $PORT | lz4 |\ 
## PIPE THROUGH DECOMPRESSOR TO DD ## 
>    dd bs=$bs of=/mnt/local/target.file \
## AND BE SURE DD'S FLAGS DECLARE RAW IO ##
>        conv=fsync oflag=direct,sync,nocache

## OUR RECEIVER'S WAITING; DIAL REMOTE TO BEGIN ##
% ssh user@remote.host <<-REMOTECMD
## JUST REVERSED; NO RAW IO FLAGS NEEDED HERE, THOUGH ## 
>    dd if=/remote/source.file bs=$bs |\
>    lz4 -9 | nc local.target.domain $PORT
> REMOTECMD  

如果尝试一下,您可能会发现netcat的数据传输速度比ssh快。无论如何,其他想法已经被采纳了,那为什么不呢?

[编辑]:我注意到另一篇文章中提到了lftp,scp和ssh,并认为我们正在谈论远程副本。本地更容易:

% bs=$(blockdev --getoptio /local/target/dev)
% dd if=/src/fi.le bs=$bs iflag=fullblock of=/tgt/fi.le \
>    conv=fsync oflag=direct,sync,nocache

[EDIT2]:归功于此:刚注意到ptman在评论中用了五个小时就击败了我。

绝对可以在这里用乘数来调整$ bs的性能-但是某些文件系统可能要求它是目标fs扇区大小的倍数,因此请记住这一点。


在我的机器,该标志是--getioopt,不是--getoptio
迈克尔Mior

2

问题在于,副本将“运行中”的块填满了您的内存,从而挤出了“有用”的数据。已知(和非常的(在这种情况下,USB)的I / O,以慢设备的Linux内核处理很难修复)的bug。

也许您可以尝试复制副本,例如通过如下脚本(概念验证草图,完全未经测试!):

while true do
  dd if=infile of=outfile bs=4096 count=... seek=... skip=...
  sleep 5
done

调整seekskip通过count每一轮。需要调整,count以使其不会填满(太多)内存,并5使其耗尽。


2

降低脏页限制。默认限制是疯狂的。

使用以下命令创建/etc/sysctl.d/99-sysctl.conf:

vm.dirty_background_ratio = 3
vm.dirty_ratio = 10

然后运行sysctl -p或重新启动。

发生的情况是,数据读取速度快于其写入目标磁盘的速度。当linux复制文件时,它所做的就是将它们读入RAM,然后将页面标记为脏页以写入目标位置。脏页无法换出。因此,如果源磁盘比目标磁盘快,并且您要复制的数据多于可用RAM,则复制操作将耗尽所有可用RAM(或至少不管脏页限制如何,这可能超过可用内存),并导致饥饿,因为脏页无法交换出去,干净页在被释放时会被使用并标记为脏页。

请注意,他不会完全解决问题... Linux真正需要的是某种仲裁仲裁脏页的方法,因此发生的大量传输不会耗尽所有可用的RAM /所有允许的脏页。


0

此问题与硬件或软件中的错误或故障无关,只是您的内核在尝试对您友好,并在后台提示您并在后台复制(它使用内核内缓存:更多RAM,更多缓存,但您可以通过在/ proc中的某个位置进行写入来限制它-尽管不建议使用)。闪存驱动器太慢,内核在其上写入数据时,其他IO操作无法足够快地执行。ionice在其他答案中多次提到也可以。但是您是否尝试过仅通过安装驱动器-o sync来避免操作系统缓冲?这可能是最简单的解决方案。


启用-o sync后,我的Internet速度快于对此USB驱动器的写入速度。我不明白的是,为什么内核不跟踪刷新缓存页面的速度,并因此而调度未来的刷新。就像它总是全速运转,即使这个不良的驱动器无法跟上速度。但这是我猜另一个问题的话题。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.