Franchement, tu sais d'où vient la performance de rsync ?

Temps de lecture estimé : 4 minutes

Personnellement, rsync me fascine. Au premier regard, c’est une simple copie à travers le réseau, mais sous le capot c’est plus que ça : s’il a écrasé tous les autres sur le même secteur, c’est parce qu’il fait de la synchronisation différentielle. C’est ça sa killer feature.

À l’ère où nous avons des réseaux de diverses bandes passantes et des fichiers de toutes tailles, un mécanisme de transfert intelligent comme celui de rsync est bienvenu. Au lieu de copier tous les fichiers et gâcher de précieuses ressources, il sélectionne les fichiers qui doivent être transmis pour mener au résultat visé, le clonage parfait des deux répertoires de travail.

Reste à savoir comment.

Quand on pense différentiel, on s’imagine forcément qu’il y a un daemon côté serveur distant, mais rsync ne semble pas en avoir besoin. En fait, il suffit d’installer le paquet afférant pour qu’il soit directement utilisable :

$ apt install rsync 
$ rsync source host:/dest

Au commencement était La Connexion

Alors comment ça marche ? Tout se joue à l’étape de la connexion, bien avant de tenter le moindre envoi de fichier. Durant cette connexion, rsync va créer à la volée un daemon sur le serveur de destination et établir une communication bidirectionnelle.

À partir de ce moment-là, les rôles sont attribués au sein de rsync : l’hôte source sera l’émetteur, l’hôte distant sera le receveur. Au moyen d’une communication constante, c’est ce processus distant qui va permettre nombre d’opérations, y compris les comparaisons et sélections.

La liste des fichiers

Cette communication établie, l’émetteur crée la liste des fichiers concernés par la synchronisation. Il parcourt récursivement le répertoire source et stocke pour chaque fichier des informations utiles pour la suite :

  • le nom,
  • le répertoire parent,
  • la date de dernière modification,
  • les permissions,
  • le type de fichier,
  • et quelques drapeaux.
// https://github.com/WayneD/rsync/blob/42f8386823b6776ee9b63c3e005557e2f5af859a/rsync.h#L800
struct file_struct {
	const char *dirname;	/* The dir info inside the transfer */
	time_t modtime;		/* When the item was last modified */
	uint32 len32;		/* Lowest 32 bits of the file's length */
	uint16 mode;		/* The item's type and permissions */
	uint16 flags;		/* The FLAG_* bits for this item */
#ifdef USE_FLEXIBLE_ARRAY
	const char basename[];	/* The basename (AKA filename) follows */
#else
	const char basename[1];	/* A kluge that should work like a flexible array */
#endif
};

Cette liste est ensuite transmise au receveur pour y être comparée. Si le fichier existe de ce côté et que les informations sont identiques, le fichier est noté « à ignorer » dans la liste retournée à l’émetteur, autrement il fait partie des candidats au transfert. Si tu as déjà lu la sortie de rsync, c’est cet ensemble d’étapes qui se cache derrière le message de rapport building file list ... done.

NB : Les comparaisons sont plus ou moins profondes selon les options, il est important de choisir le bon ratio entre pertinence et performance.

liste fichier à transmettre rsync

Cette sélection simple et ingénieuse donne déjà tout son sens à l’expression synchronisation différentielle, mais rsync ne s’arrête pas là. Et si je te disais qu’il n’envoie en réalité que les blocs différents des fichiers candidats ?

La transmission delta

En fait, le receveur ne fait pas qu’envoyer la liste des fichiers contenant des changements, il envoie aussi avec chaque fichier les empreintes des blocs de ce dernier. Le receveur faisant foi, son fichier est considéré comme la référence pour la comparaison. Pour cette raison, l’émetteur compare ses propres blocs avec la référence et complète un accumulateur :

accumulation des blocs deltas avant transmission rsync

Si la référence et le candidat correspondent, l’accumulateur est transmis au receveur et on passe au bloc de référence suivant. Une fois reçu, le receveur exploite cet accumulateur pour reconstruire la toute dernière version du fichier, un peu à la manière des applications successives des diff git.

En dépit de son apparence monolithique, rsync est en réalité une composition de plusieurs rôles et processus dont l’objectif global est la plus intime et performante compréhension de ce qu’est une synchronisation : une transmission des deltas. Et il remplit sa tâche avec brio.

Comme d’habitude, vous pouvez retrouver le code pour essayer par vous-même sur le dépôt d’exemple.


Source :


    Ce billet vous a plu ? Partagez-le sur les réseaux…


    … Ou inscrivez-vous à la newsletter pour ne manquer aucun article (Si vous ne voyez pas le formulaire, désactivez temporairement uBlock).

    Voir aussi