Paralelize o rsync usando o GNU Parallel

18

Eu tenho usado um rsyncscript para sincronizar dados em um host com os dados em outro host. Os dados possuem vários arquivos de tamanho pequeno que contribuem para quase 1,2 TB.

Para sincronizar esses arquivos, eu tenho usado o rsynccomando da seguinte maneira:

rsync -avzm --stats --human-readable --include-from proj.lst /data/projects REMOTEHOST:/data/

O conteúdo de proj.lst é o seguinte:

+ proj1
+ proj1/*
+ proj1/*/*
+ proj1/*/*/*.tar
+ proj1/*/*/*.pdf
+ proj2
+ proj2/*
+ proj2/*/*
+ proj2/*/*/*.tar
+ proj2/*/*/*.pdf
...
...
...
- *

Como teste, peguei dois desses projetos (8,5 GB de dados) e executei o comando acima. Por ser um processo seqüencial, utiliza 14 minutos e 58 segundos para concluir. Portanto, para 1,2 TB de dados, levaria várias horas.

Se eu pudesse vários rsyncprocessos em paralelo (usando &, xargsou parallel), ele iria salvar o meu tempo.

Eu tentei com o comando abaixo com parallel(após cding para o diretório de origem) e levou 12 minutos e 37 segundos para executar:

parallel --will-cite -j 5 rsync -avzm --stats --human-readable {} REMOTEHOST:/data/ ::: .

Isso deveria levar cinco vezes menos tempo, mas não levou. Eu acho que estou errado em algum lugar.

Como posso executar vários rsyncprocessos para reduzir o tempo de execução?

Mandar Shinde
fonte
11
Você está limitado pela largura de banda da rede? Iops de disco? Largura de banda do disco?
precisa
Se possível, gostaríamos de usar 50% da largura de banda total. Mas, paralelizar múltiplos rsyncs é nossa primeira prioridade.
precisa
Você pode nos informar: largura de banda de rede, IOPs de disco, largura de banda de disco e largura de banda realmente usada?
precisa
Na verdade, eu não sei sobre os parâmetros acima. Por enquanto, podemos negligenciar a parte de otimização. rsyncS múltiplos em paralelo é o foco principal agora.
Mandar Shinde
Não adianta ficar paralelo se a limitação não for a CPU. Isso pode / vai piorar ainda mais (movimentos conflitantes do braço do disco no disco de origem ou de destino).
Xenoid #

Respostas:

16

As etapas a seguir fizeram o trabalho para mim:

  1. Execute o rsync --dry-runprimeiro para obter a lista de arquivos que seriam afetados.
$ rsync -avzm --stats --safe-links --ignore-existing --dry-run \
    --human-readable /data/projects REMOTE-HOST:/data/ > /tmp/transfer.log
  1. Alimentei a saída de cat transfer.logpara parallelpara executar 5 rsyncs em paralelo, da seguinte maneira:
$ cat /tmp/transfer.log | \
    parallel --will-cite -j 5 rsync -avzm --relative \
      --stats --safe-links --ignore-existing \
      --human-readable {} REMOTE-HOST:/data/ > result.log

Aqui, a --relativeopção ( link ) assegura que a estrutura de diretórios dos arquivos afetados, na origem e no destino, permaneça a mesma ( /data/diretório interno ), portanto, o comando deve ser executado na pasta de origem (por exemplo /data/projects).

Mandar Shinde
fonte
5
Isso faria um rsync por arquivo. Provavelmente seria mais eficiente dividir a lista de arquivos inteira usando splite alimentando esses nomes de arquivos para paralelo. Em seguida, use rsync's --files-frompara obter os nomes de arquivos de cada arquivo e sincronizá-los. backups rm. * backups split -l 3000 backup.list. ls backups. * | paralela --line-tampão --verbose -j 5 rsync --progress -av --files-de {} / local / PAI / PATH / REMOTE_HOST: REMOTE_PATH /
Sandip Bhattacharya
11
Como o segundo comando rsync lida com as linhas result.log que não são arquivos? ie receiving file list ... done created directory /data/.
Mike D
11
Nas versões mais recentes do rsync (3.1.0+), você pode usar --info=nameno lugar de -ve obterá apenas os nomes dos arquivos e diretórios. Você pode usar --protect-args para o rsync de transferência 'interno' também se algum arquivo tiver espaços ou metacaracteres de shell.
Cheetah
13

Eu pessoalmente uso este simples:

ls -1 | parallel rsync -a {} /destination/directory/

O que só é útil quando você tem mais do que alguns diretórios não-quase vazios; caso contrário, você terá quase todas as rsyncterminações e o último fará todo o trabalho sozinho.

Julien Palard
fonte
Isso funciona muito bem - é difícil saber se está fazendo alguma coisa, então um -v para paralelo o torna mais falador. Além disso, -j 30 para paralelo (isto é, antes do comando rsync) faz executar 30 trabalhos, não apenas um por núcleo da CPU, que é o padrão.
Criggie 22/01
12

Eu desencorajaria alguém a usar a resposta aceita, uma solução melhor é rastrear o diretório de nível superior e lançar um número proporcional de operações de rync.

Eu tenho um grande volume zfs e minha fonte era uma montagem cifs. Ambos estão vinculados ao 10G e, em alguns benchmarks, podem saturar o link. O desempenho foi avaliado usando zpool iostat 1.

A unidade de origem foi montada como:

mount -t cifs -o username=,password= //static_ip/70tb /mnt/Datahoarder_Mount/ -o vers=3.0

Usando um único rsyncprocesso:

rsync -h -v -r -P -t /mnt/Datahoarder_Mount/ /StoragePod

o medidor io lê:

StoragePod  30.0T   144T      0  1.61K      0   130M
StoragePod  30.0T   144T      0  1.61K      0   130M
StoragePod  30.0T   144T      0  1.62K      0   130M

Nos benchmarks sintéticos (disco de cristal), o desempenho para gravação sequencial se aproxima de 900 MB / s, o que significa que o link está saturado. 130MB / s não é muito bom, e a diferença entre esperar um fim de semana e duas semanas.

Então, criei a lista de arquivos e tentei executar a sincronização novamente (eu tenho uma máquina com 64 núcleos):

cat /home/misha/Desktop/rsync_logs_syncs/Datahoarder_Mount.log | parallel --will-cite -j 16 rsync -avzm --relative --stats --safe-links --size-only --human-readable {} /StoragePod/ > /home/misha/Desktop/rsync_logs_syncs/Datahoarder_Mount_result.log

e teve o mesmo desempenho!

StoragePod  29.9T   144T      0  1.63K      0   130M
StoragePod  29.9T   144T      0  1.62K      0   130M
StoragePod  29.9T   144T      0  1.56K      0   129M

Como alternativa, simplesmente executei o rsync nas pastas raiz:

rsync -h -v -r -P -t /mnt/Datahoarder_Mount/Mikhail/Marcello_zinc_bone /StoragePod/Marcello_zinc_bone
rsync -h -v -r -P -t /mnt/Datahoarder_Mount/Mikhail/fibroblast_growth /StoragePod/fibroblast_growth
rsync -h -v -r -P -t /mnt/Datahoarder_Mount/Mikhail/QDIC /StoragePod/QDIC
rsync -h -v -r -P -t /mnt/Datahoarder_Mount/Mikhail/sexy_dps_cell /StoragePod/sexy_dps_cell

Isso realmente aumentou o desempenho:

StoragePod  30.1T   144T     13  3.66K   112K   343M
StoragePod  30.1T   144T     24  5.11K   184K   469M
StoragePod  30.1T   144T     25  4.30K   196K   373M

Concluindo, como o @Sandip Bhattacharya levantou, escreva um pequeno script para obter os diretórios e paralelo a ele. Como alternativa, passe uma lista de arquivos para o rsync. Mas não crie novas instâncias para cada arquivo.

Mikhail
fonte
5

Uma maneira testada de executar o rsync paralelo é: http://www.gnu.org/software/parallel/man.html#EXAMPLE:-Parallelizing-rsync

O rsync é uma ótima ferramenta, mas às vezes não preenche a largura de banda disponível. Isso geralmente é um problema ao copiar vários arquivos grandes em conexões de alta velocidade.

A seguir, será iniciado um rsync por arquivo grande no src-dir para dest-dir no servidor fooserver:

cd src-dir; find . -type f -size +100000 | \
parallel -v ssh fooserver mkdir -p /dest-dir/{//}\; \
  rsync -s -Havessh {} fooserver:/dest-dir/{} 

Os diretórios criados podem ter permissões incorretas e arquivos menores não estão sendo transferidos. Para corrigir aqueles que executam o rsync uma última vez:

rsync -Havessh src-dir/ fooserver:/dest-dir/ 

Se você não conseguir enviar os dados por push, mas precisar extraí-los e os arquivos forem chamados digits.png (por exemplo, 000000.png), você poderá:

seq -w 0 99 | parallel rsync -Havessh fooserver:src/*{}.png destdir/
Ole Tange
fonte
Alguma outra alternativa para evitar find?
Mandar Shinde
11
Limite -maxdepth de localização.
precisa
Se eu usar --dry-run opção rsync, eu teria uma lista de arquivos que seriam transferidos. Posso fornecer essa lista de arquivos parallelpara paralelizar o processo?
Mandar Shinde
11
arquivos para gatos | paralelo -v ssh fooserver mkdir -p / dest-dir / {//} \; rsync -s -Havessh {} servidor de arquivos: / dest-dir / {}
Ole Tange
Você pode explicar a mkdir -p /dest-dir/{//}\;parte? Especialmente o{//} coisa é um pouco confusa.
Mandar Shinde
1

Para sincronizações de vários destinos, estou usando

parallel rsync -avi /path/to/source ::: host1: host2: host3:

Dica: Todas as conexões ssh são estabelecidas com chaves públicas em ~/.ssh/authorized_keys

ingopingo
fonte
1

Eu sempre busco o rsync paralelo no google, pois sempre esqueço o comando completo, mas nenhuma solução funcionou para mim como eu queria - ou inclui várias etapas ou precisa instalar parallel. Acabei usando este one-liner para sincronizar várias pastas:

find dir/ -type d|xargs -P 5 -I % sh -c 'rsync -a --delete --bwlimit=50000 $(echo dir/%/ host:/dir/%/)'

-P 5 é a quantidade de processos que você deseja gerar - use 0 para ilimitado (obviamente não recomendado).

--bwlimit para evitar usar toda a largura de banda.

-I % argumento fornecido por find (diretório encontrado em dir/ )

$(echo dir/%/ host:/dir/%/)- imprime diretórios de origem e destino que são lidos pelo rsync como argumentos. % é substituído porxargs com o nome do diretório encontrado por find.

Vamos supor que eu tenha dois diretórios em /home: dir1e dir2. Eu corro find /home -type d|xargs -P 5 -I % sh -c 'rsync -a --delete --bwlimit=50000 $(echo /home/%/ host:/home/%/)'. Portanto, o comando rsync será executado como dois processos (dois processos porque /homepossui dois diretórios) com os seguintes argumentos:

rsync -a --delete --bwlimit=50000 /home/dir1/ host:/home/dir1/
rsync -a --delete --bwlimit=50000 /home/dir1/ host:/home/dir1/
Sebastjanas
fonte