web-dev-qa-db-fra.com

Paralléliser rsync

Je viens d'emménager et j'ai découvert, après quelques essais et erreurs, que quelque part entre ma maison et mon serveur distant, il y avait des étranglements ... mais les étranglements ne sont pas très intelligents. Il ne fait que restreindre les connexions individuelles. Donc, si je copie un fichier de 1 Go, il fonctionnera joyeusement à 150 kbps. Mais si j’initialise 10 copies, chacune d’elles passera à 150 Kbits/s (c’est-à-dire que je reçois une bande passante globale beaucoup plus élevée sur plusieurs connexions).

J'utilise assez souvent rsync pour synchroniser de grands ensembles de données du travail à la maison (heureusement sous la forme de nombreux fichiers). Y a-t-il un moyen de dire à rsync de télécharger en utilisant plusieurs connexions? Théoriquement, cela devrait être possible puisque, autant que je sache, rsync effectue d'abord une passe pour déterminer les modifications nécessaires, puis effectue la transmission proprement dite. Points bonus s'il existe un moyen magique de dire à rsync de découper des fichiers individuels en N morceaux, puis de les fusionner. Je pense que CuteFTP est en fait assez intelligent pour réussir cela.

30
stuyguy

J'ai simplement eu un problème similaire à cause du déplacement de plusieurs TB d'un NAS vers un autre NAS sans capacité de sauvegarde/restauration qui me permettrait de simplement alimenter 1 mis à l'autre.

J'ai donc écrit ce script pour exécuter 1 rsync pour chaque répertoire rencontré. Cela dépend de pouvoir lister les répertoires sources (attention d’échapper à ARG 3), mais je pense que vous pouvez définir cette étape avec un rsync non récursif qui ne fait que copier les fichiers et les répertoires au niveau approprié.

Il détermine également le nombre de rsync à exécuter en fonction du nombre de processeurs, mais vous pouvez modifier ce paramètre.

L’autre option possible qui me vient à l’esprit est la suivante: exécuter un rsync en mode --list-only.

Ensuite, exécutez 1 rsync pour chaque fichier de votre liste. Si vous utilisiez xargs pour gérer le nombre de rsync que vous aviez, cela pourrait être très élégant. En fait probablement une solution plus élégante que mon petit script ici ...

#! /bin/bash
SRC_DIR=$1
DEST_DIR=$2
LIST=$3
CPU_CNT=`cat /proc/cpuinfo|grep processor |wc -l`
#  pseudo random heuristic
let JOB_CNT=CPU_CNT*4
[ -z "$LIST" ] && LIST="-tPavW --exclude .snapshot --exclude hourly.?"
echo "rsyncing From=$SRC_DIR To=$DEST_DIR DIR_LIST=$LIST"
mkdir -p /{OLD,NEW}_NAS/home
[ -z "$RSYNC_OPTS" ] && RSYNC_OPTS="-tPavW --delete-during --exclude .snapshot --exclude hourly.?"
cd $SRC_DIR
echo $LIST|xargs -n1 echo|xargs -n1 -P $JOB_CNT -I% rsync ${RSYNC_OPTS} ${SRC_DIR}/%/ ${DEST_DIR}/%/
13
kkron

GNU Parallel a une solution .

J'ai déplacé 15 TB à 1 Gbps et il peut saturer le lien 1 Gbps.

Ce qui suit va démarrer un rsync par gros fichier dans src-dir vers dest-dir sur le serveur serveur:

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

Les répertoires créés peuvent se retrouver avec des autorisations incorrectes et des fichiers plus petits ne sont pas transférés. Pour réparer ceux-ci, lancez une dernière fois rsync:

rsync -Havessh src-dir/ fooserver:/dest-dir/
6
Ole Tange

Oui. Une telle caractéristique existe.

Il existe un utilitaire appelé pssh fournissant les fonctionnalités décrites.

Ce paquet fournit des versions parallèles des outils openssh. Inclus dans la distribution:

  • Ssh parallèle (pssh)
  • SCP parallèle (pscp)
  • parallèle rsync (prsync)
  • Nuke parallèle (pnuke)
  • Slurp parallèle (pslurp)

Je ne sais pas à quel point il est facile à installer, mais cela pourrait faire l'affaire!

3
Tim Bielawa

Je ne peux pas commenter, j'ai donc ajouté une nouvelle réponse, avec un code un peu meilleur que le précédent (Nice & smart).

Vérifiez la ligne rsync, car elle contient un optionnel ionice Tweak.

#!/bin/bash
start_time=$(date +%s.%N)
# Transfer files in parallel using rsync (simple script)
# MAXCONN: maximum number "rsync" processes running at the same time:
MAXCONN=6
# Source and destination base paths. (not need to end with "/")
SRC_BASE=/home/user/public_html/images
[email protected]:/home/user/public_html/images
RSYNC_OPTS="-ah --partial"
# Main loop:
for FULLDIR in $SRC_BASE/*; do
    NUMRSYNC=`ps -Ao comm | grep '^'rsync'$' | wc -l `
    while [ $NUMRSYNC -ge $MAXCONN ]; do
        NUMRSYNC=`ps -Ao comm | grep '^'rsync'$' | wc -l `
        sleep 1
    done
    DIR=`basename $FULLDIR`
    echo "Start: " $DIR
    ionice -c2 -n5 rsync $RSYNC_OPTS $SRC_BASE/${DIR}/ $DST_BASE/${DIR}/ &
    # rsync $RSYNC_OPTS $SRC_BASE/${DIR}/ $DST_BASE/${DIR}/ &
    sleep 5
done

execution_time=$(echo "$(date +%s.%N) - $start" | bc)
printf "Done. Execution time: %.6f seconds\n" $execution_time
3
Widmo

On dirait que quelqu'un a écrit cet utilitaire pour vous. Il casse le transfert en morceaux parallèles. Ceci est une meilleure implémentation que la version "parallel big file" listée sous GNU Parallel:

https://Gist.github.com/rcoup/5358786

En outre, lftp peut paralléliser les transferts de fichiers via ftp, ftps, http, https, hftp, fish, sftp. Il arrive souvent que l'utilisation de lftp présente certains avantages, car la gestion des autorisations, l'accès restreint, etc. pour rsync peut être difficile.

2
Erik Aronesty

Non, une telle fonctionnalité n'existe pas. Vous pouvez fractionner la synchronisation en plusieurs appels à rsync si vous le souhaitez vraiment.

Je vous suggérerais de trouver ce qui limite le débit et de discuter sérieusement avec quiconque le maintient/le gère.

1
David Schwartz

Je voulais transférer plusieurs répertoires (avec plusieurs fichiers) en même temps, alors j'ai créé ce petit script:

#!/bin/bash
# Transfer files in parallel using rsync (simple script)
# MAXCONN: maximum number "rsync" processes running at the same time:
MAXCONN=10
# Source and destination base paths. (not need to end with "/")
SRC_BASE=/home/sites
[email protected]:/var/www
RSYNC_OPTS="--stats -ilrtpog"
# Main loop:
for FULLDIR in $SRC_BASE/*/; do
    NUMRSYNC=`ps -Ao comm | grep '^'rsync'$' | wc -l `
    while [ $NUMRSYNC -ge $MAXCONN ]; do
        NUMRSYNC=`ps -Ao comm | grep '^'rsync'$' | wc -l `
        sleep 10
    done
    DIR=`basename $FULLDIR`
    rsync $RSYNC_OPTS $SRC_BASE/${DIR}/ $DST_BASE/${DIR}/ & 
    sleep 1 
done
echo "Done."

J'ai fait ce script assez rapidement, donc veuillez le réviser et le tester avant de l'utiliser dans un environnement de production.

1
lepe

J'ai créé le script suivant pour télécharger plusieurs dossiers avec des images en parallèle. Vous l'exécutez d'abord avec la cible de synchronisation, puis avec tous les noms de dossiers à copier.

#!/bin/sh

dest="$1"
shift

if [ "$dest" = "" ]; then
    echo "USAGE: $0 TARGET:/foo/bar <dir1> [dir2] [dir3]"
    exit 1
fi

RCol='\x1B[0m' # Text Reset
BYel='\x1B[1;33m';

for i in "$@"; do
    prefix=`printf "$BYel%50s:$RCol" "$i"`
    echo "$prefix * Starting $i"
    echo "$prefix -> syncing '$i/' to '$dest/$i/'"
    (rsync -rv "$i/" "$dest/$i/") 2>&1 | sed "s/^/$prefix /g" &
    sleep 0.5
done

echo "* Waiting for all to complete"
wait

Il préfixe le nom du dossier en jaune à toutes les sorties de la console rsync pour le rendre plus joli.

0
konrad