Tornar a cópia do disco / disco mais lenta

28

Existe um método para retardar o processo de cópia no Linux?

Eu tenho um arquivo grande, digamos 10 GB, e gostaria de copiá-lo para outro diretório, mas não quero copiá-lo com velocidade total. Digamos que eu gostaria de copiá-lo com a velocidade de 1mb / s, não mais rápido. Eu gostaria de usar um cpcomando padrão do Linux .

Isso é possível? (Se sim, como?)

Edit : então, adicionarei mais contexto ao que estou tentando alcançar.

Eu tenho um problema no sistema ArchLinux ao copiar arquivos grandes por USB (para um pendrive, disco USB, etc.). Depois de encher o cache do buffer usb, meu sistema pára de responder (até o mouse para; ele se move esporadicamente). A operação de cópia ainda está em andamento, mas são necessários 100% dos recursos da caixa. Quando a operação de cópia termina, tudo volta ao normal - tudo responde perfeitamente perfeitamente.

Talvez seja um erro de hardware, não sei, mas sei que tenho duas máquinas com esse problema (ambas estão no ArchLinux, uma é uma caixa de desktop e a segunda é um laptop).

A "solução" mais fácil e rápida para isso (eu concordo que não é a solução 'real', apenas um 'hack' feio) seria impedir que esse buffer fosse preenchido copiando o arquivo com uma velocidade média de gravação da unidade USB, por eu seria o suficiente.

antonone
fonte
7
Se você estiver tentando limitar a velocidade de cópia de disco para disco, em um esforço para ser "legal" com outros processos de E / S no sistema, provavelmente será melhor aproveitar a capacidade do kernel de ajustar o agendamento de E / S em vez de. Especificamente, ionicepode ser usado para garantir que seu processo de cópia de disco para disco seja agendado de E / S com uma prioridade mais baixa que os processos regulares.
Steven segunda-feira,
3
Esta é uma pergunta clássica sobre o problema XY . Em vez disso, você deve perguntar por que sua área de trabalho não responde quando você copia arquivos para um dispositivo USB.
Michael Hampton
4
Atualmente, o Linux tem buffers de E / S ridiculamente grandes. Os tamanhos de RAM cresceram mais rapidamente que as velocidades de armazenamento em massa. Talvez você possa executar a cópia usando dd (1) e sync, para que ela seja sincronizada periodicamente em vez de ser armazenada em buffer? E o visualizador de tubos (pv) tem uma opção de limitação de taxa. Algo como cat file | pv -L 3k > outfile. Nem são os mesmos que usar cp (1).
Ptman #
@ MichaelHampton, existem vários tópicos não resolvidos sobre esse assunto no fórum do ArchLinux, então imaginei que tentarei lidar com isso de uma maneira diferente, apenas para fazê-lo funcionar.
antonone
@antonone Mas o Unix.SE não é o fórum do ArchLinux. Alguém aqui pode ter uma solução.
Izkata

Respostas:

23

Você pode estrangular um tubo com pv -qL(ou cstream -tfornece funcionalidade semelhante)

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

-q remove os relatórios de progresso do stderr.

O -Llimite está em bytes.

Mais sobre a --rate-limit/-Lbandeira do 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.

Esta resposta apontou originalmente, throttlemas esse projeto não está mais disponível e, portanto, escapou de alguns sistemas de pacotes.

Matt
fonte
Se cpnão for possível diminuir a velocidade, acho que usar um comando personalizado é a única opção.
antonone
1
Soa muito complicado em comparação com orsync
LinuxSecurityFreak 15/16/16
parece mais complicado, mas mais utilizável para mim. É necessário testar um mecanismo de bloqueio de arquivo e diminuir a cópia para alguns bytes / s, o que parece impossível com o rsync. Vou tentar e 'cat' um arquivo através do tubo do acelerador
cljk 18/07
É triste dizer, mas o projeto está morto bugs.debian.org/cgi-bin/bugreport.cgi?bug=426891
cljk
1
@cljk atualizado para pv. obrigado.
Matt
23

Em vez de cp -a /foo /barvocê também pode usar rsynce limitar a largura de banda conforme necessário.

No rsyncmanual do:

--bwlimit=KBPS

largura de banda limite de E / S; KBytes por segundo

Portanto, o comando actuall, também mostrando o progresso, ficaria assim:

rsync -av --bwlimit=100 --progress /foo /bar
LinuxSecurityFreak
fonte
Parece uma boa idéia para copiar discos antigos que não quero bater.
precisa saber é o seguinte
Não funciona para ler /dev/zeroou/dev/random
cdosborn
rsync -a --bwlimit=1500 /source /destinationfunciona perfeitamente para copiar pastas gigantes em um MB / s de velocidade de 1,5 (o que é um bom compromisso entre evitando qualquer devagar servidor e não levando muito tempo)
lucaferrario
Nota: mesmo que a página de manual possa dizer que você pode usar letras para unidades, por exemplo 20m, ela não é suportada em todas as plataformas, portanto, atenha-se à notação KBytes.
Hubert Grzeskowiak
salvou o meu dia! cgroup cgexec -g ... cp /in /outnão estava funcionando o tempo todo (do terminal trabalhou algumas vezes, a partir do script nunca mais) e não tenho idéia do porquê ...
Aquarius Poder
13

Eu diria que você está tentando não interromper outras atividades. As versões recentes do Linux incluem o ioniceque permite controlar o agendamento de E / S.

Além de permitir várias prioridades, há uma opção adicional para limitar a E / S às vezes em que o disco está inativo. O comando man ioniceexibirá a documentação.

Tente copiar o arquivo usando um comando como:

ionice -c 3 cp largefile /new/directory

Se os dois diretórios estiverem no mesmo dispositivo, você pode achar que vincular o arquivo faz o que você deseja. Se você estiver copiando para fins de backup, não use esta opção. lné extremamente rápido, pois o arquivo em si não é copiado. Experimentar:

ln largefile /new/directory

Ou, se você quiser acessá-lo de um diretório em um dispositivo diferente, tente:

ln -s largefile /new/directory
BillThor
fonte
ionice funciona bem no linux? eu li apenas "emular" o trabalho e não há diferença real? +1 para links
Nick
1
@ Nick Quando eu o usei, ele se comportou como esperado. O processo no qual apliquei o ionice diminuiu significativamente, e os outros processos que precisavam de E / S foram capazes de executar conforme o esperado. Com uma carga de E / S moderada de outros processos, pude efetivamente suspender um processo de E / S alto aplicando a máxima 'gentileza' conforme o esperado. Uma vez que não havia E / S concorrentes, o processo ionizado funcionava normalmente.
BillThor
com o arquivo de 400MB que eu estava copiando de um HD para um SSD, os 10s iniciais funcionavam perfeitamente; então, de repente, vi uma alta carga de IO e tive que esperar uma minuciosa máquina congelada: /. Eu tenho o mesmo problema com o cgroup write io throttle, onde funciona algumas vezes e outras não funciona.
Aquarius Power
7

Se a ionicesolução não for suficiente (por que razão) e você realmente quiser limitar a E / S a um valor absoluto, existem várias possibilidades:

  1. o provavelmente mais fácil: ssh. Ele tem um limite de largura de banda embutido. Você usaria, por exemplo, tar(em vez de cp) ou scp(se isso for bom o suficiente; eu não sei como ele lida com links simbólicos e links físicos) ou rsync. Esses comandos podem canalizar seus dados ssh. No caso de tarvocê escrever para /dev/stdout(ou -) e canalizar para o sshcliente que executa outro tarno lado "remoto".

  2. elegante, mas não no kernel da baunilha (AFAIK): o destino do mapeador de dispositivos ioband. Obviamente, isso funciona apenas se você puder desmontar o volume de origem ou de destino.

  3. um pouco de diversão auto-escrita: grep "^write_bytes: " /proc/$PID/iofornece a quantidade de dados que um processo gravou. Você pode escrever um script que começa cpem segundo plano, dorme por exemplo 1/10 de segundo, interrompe o cpprocesso em segundo plano ( kill -STOP $PID), verifica a quantidade que foi escrita (e lê? Sobre o mesmo valor nesse caso), calcula por quanto tempo cpdeve fazer uma pausa para reduzir a taxa de transferência média até o valor pretendido, dormir durante esse tempo, acordar cp( kill -CONT $PID) e assim por diante.

Hauke ​​Laging
fonte
Sim, normalmente estou usando o lftp para conectar-se ao localhost via scp e limitar o bandwich a partir daí.
antonone
5

Seu problema provavelmente não está no seu computador, por si só, provavelmente está bom. Mas essa camada de transição flash USB possui um processador próprio que precisa mapear todas as suas gravações para compensar o que poderia ser tanto quanto um chip flash com falha de 90%, quem sabe? Você o inunda, depois inunda seus amortecedores, inunda todo o ônibus e fica preso, cara - afinal, é aí que estão todas as suas coisas. Pode parecer contra-intuitivo, mas o que você realmente precisa é bloquear a E / S - você precisa deixar o FTL definir o ritmo e, em seguida, apenas prosseguir.

(Sobre hackers de microcontroladores FTL: http://www.bunniestudios.com/blog/?p=3554 )

Todas as respostas acima devem funcionar, então isso é mais um "eu também!" do que qualquer outra coisa: eu estive totalmente lá, cara. Resolvi meus próprios problemas com o rsync --bwlimit arg (2,5mbs parecia ser o ponto ideal para uma única execução sem erros - qualquer coisa mais e eu acabaria com erros de proteção contra gravação). O rsync foi especialmente adequado ao meu objetivo, porque eu estava trabalhando com sistemas de arquivos inteiros - portanto, havia muitos arquivos - e simplesmente executar o rsync uma segunda vez corrigia todos os problemas da primeira execução (o que era necessário quando eu ficava impaciente e tentava ultrapassar 2,5mbs).

Ainda assim, acho que isso não é tão prático para um único arquivo. No seu caso, você pode simplesmente canalizar para dd definido como raw-write - você pode manipular qualquer entrada dessa maneira, mas apenas um arquivo de destino por vez (embora esse arquivo único possa ser um dispositivo de bloco inteiro, é claro).

## 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 [email protected] <<-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  

Você pode achar que o netcat é um pouco mais rápido que o ssh para o transporte de dados, se você tentar. Enfim, as outras idéias já foram tomadas, então por que não?

[EDIT]: notei as menções de lftp, scp e ssh no outro post e pensei que estávamos falando sobre uma cópia remota. Local é muito mais fácil:

% 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]: Crédito onde é devido: notei que o ptman me venceu por cinco horas nos comentários.

Definitivamente, você pode ajustar o $ bs para obter o desempenho aqui com um multiplicador - mas alguns sistemas de arquivos podem exigir que ele seja um múltiplo do setor de destino do FS, portanto, lembre-se disso.

mikeserv
fonte
Na minha máquina, a bandeira --getiooptnão é--getoptio
Michael Mior 9/17
2

O problema é que a cópia está enchendo sua memória com blocos "em andamento", acumulando dados "úteis". Um bug conhecido (e muito difícil de corrigir) no manuseio de E / S do kernel Linux para diminuir a velocidade dos dispositivos (neste caso, USB).

Talvez você possa tentar dividir a cópia, por exemplo, por um script como o seguinte (esboço de prova de conceito, totalmente não testado!):

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

ajustando seeke skippor countcada rodada. Precisa ajustar countpara não encher (muita) memória e 5permitir que ela seja drenada.

vonbrand
fonte
2

Reduza o limite de páginas sujas. O limite padrão é insano.

Crie /etc/sysctl.d/99-sysctl.conf com:

vm.dirty_background_ratio = 3
vm.dirty_ratio = 10

Em seguida, execute sysctl -p ou reinicie.

O que está acontecendo é que os dados estão sendo lidos mais rapidamente do que podem ser gravados no disco de destino. Quando o linux copia arquivos, o que ele faz é lê-los na RAM e marcar as páginas como sujas para serem gravadas no destino. Páginas sujas não podem ser trocadas. Portanto, se o disco de origem for mais rápido que o de destino e você estiver copiando mais dados do que a RAM livre, a operação de cópia consumirá toda a RAM disponível (ou pelo menos seja qual for o limite de páginas sujas, que pode ser maior que o RAM disponível) e causar inanição, pois as páginas sujas não podem ser trocadas e as páginas limpas são usadas e marcadas como sujas quando são liberadas.

Note que ele não resolverá completamente o problema ... o que o linux realmente precisa é uma maneira de arbitrar a criação de páginas sujas, para que uma grande transferência ocorra não consuma toda a RAM disponível / todas as páginas sujas permitidas.

alex.forencich
fonte
0

Esse problema não tem nada a ver com erros ou falhas no hardware ou no software, é apenas o seu kernel tentando ser gentil com você e devolver a sua solicitação e copiar em segundo plano (ele usa um cache no kernel: mais RAM, mais cache, mas você pode limitá-lo escrevendo em algum lugar em / proc - embora não seja recomendado). As unidades flash são muito lentas e, enquanto o kernel grava nele, outras operações de E / S não podem ser executadas com rapidez suficiente. ionicemencionado várias vezes em outras respostas está ok. Mas você já tentou montar a unidade -o syncpara evitar o buffer do SO? É provavelmente a solução mais simples que existe.

orion
fonte
Depois de ativar a sincronização -o, minha Internet fica mais rápida que a velocidade de gravação nesta unidade USB. O que eu não entendo é por que o kernel não controla a rapidez com que as páginas de cache estão sendo liberadas e programa futuras liberações com base nisso. É como se sempre estivesse em velocidade máxima, mesmo que essa unidade ruim não consiga acompanhar a velocidade. Mas esse é um tópico para outra pergunta, eu acho.
antonone