Un rsync --link-dest sans -H en aval casse toute la déduplication : sur mon NAS, les snapshots quotidiens des données Nextcloud (108 Go) ne coûtaient que les fichiers modifiés grâce aux hardlinks, mais le script qui recopie le NAS vers un disque externe utilisait rsync -a, sans -H. Chaque snapshot y devenait une copie pleine : 108 Go × N. Le correctif tient en une lettre, puis j’ai simplifié le modèle pour que le problème ne puisse plus revenir.
Deux étages de rsync qui ne parlent pas de la même chose
Le premier étage tourne chaque nuit sur le NAS : un pull des données Nextcloud du serveur srv-a, dans un dossier daté par jour. L’option --link-dest=DIR de rsync crée un hardlink vers le fichier de DIR quand il est inchangé, au lieu de le recopier. Un hardlink est une seconde entrée de répertoire qui pointe vers les mêmes blocs sur le disque : dix snapshots d’un fichier inchangé occupent la place d’un seul.
Le second étage est backup-to-external.sh, qui copie le NAS vers des disques USB externes chiffrés en LUKS (le chiffrement a eu ses propres surprises, racontées dans l’article sur Argon2 et les cibles à 1 GB de RAM). Parmi ses sources, le dossier des homes, qui contient les snapshots du premier étage.
Ses options d’origine :
RSYNC_OPTS=(
-a
--info=stats2,progress2
--modify-window=1
--bwlimit=15000
--exclude='.Trash-*/'
--exclude='lost+found/'
--exclude='.snapshots/'
)
-a ressemble à « tout préserver ». Ce n’est pas le cas.
rsync -a préserve-t-il les hardlinks ?
Non, et la page de manuel le dit dans le résumé des options (rsync 3.2.7) :
--archive, -a archive mode is -rlptgoD (no -A,-X,-U,-N,-H)
Et dans la description de --hard-links, -H :
Without this option, hard-linked files in the source are treated as
though they were separate files.
Sur le disque externe, chaque entrée de chaque snapshot devient donc un fichier indépendant, écrit en entier. Les 108 Go dédupliqués sur le NAS se multiplient par le nombre de snapshots présents au moment de la copie.
--link-destdéduplique avec des hardlinks ; un rsync en aval sans-Hles transforme en copies. La déduplication ne survit qu’au premier étage.
Combien ça aurait coûté ?
Le commit du correctif note une explosion à 3,5 To. C’est une estimation, pas une mesure sur le disque. Le calcul brut donne le même ordre de grandeur : au moment où je m’en suis aperçu, le NAS contenait 37 snapshots (accumulés parce que la rétention ne tournait plus, voir l’article sur set -e et rsync exit 23), et 37 × 108 Go ≈ 4 To. Même avec la rétention prévue de 3 jours, chaque copie externe aurait embarqué plusieurs fois les 108 Go.
Sur le NAS, rien ne se voyait : du compte un fichier à plusieurs hardlinks une seule fois, et l’espace occupé restait raisonnable. Le problème n’existait qu’en aval, sur un disque branché de temps en temps.
Le correctif : -H, puis plus de snapshots du tout
Première étape, ajouter l’option :
RSYNC_OPTS=(
--delete # miroir : purge sur le disque ce qui n existe plus sur le NAS
-a
-H # preserver hardlinks (--link-dest) au lieu de les dupliquer
--info=stats2,progress2
--modify-window=1
--bwlimit=15000
...
)
⚠️ D’après le manuel, rsync ne détecte les hardlinks qu’à l’intérieur du même transfert. Ça fonctionne ici parce que tout le dossier des homes, snapshots compris, part en une seule commande. Un rsync par snapshot ne recréerait pas les liens entre eux.
Deuxième étape, le même jour : se demander si ces snapshots servaient à quelque chose. Pour les données Nextcloud et les configurations, la réponse était non : j’ai remplacé les dossiers datés par un miroir unique (--delete), et seuls les dumps de bases gardent 7 jours glissants. Sans snapshots, il n’y a plus de hardlinks à perdre ; -H reste en place pour le jour où un autre dossier en contiendra.
Lessons learned
rsync -ane préserve pas les hardlinks. Le mode archive vaut-rlptgoD; il faut ajouter-Hexplicitement.- Une déduplication par hardlinks ne survit pas à une copie qui ne les connaît pas. Chaque étage de la chaîne de sauvegarde doit préserver les liens, sinon la taille devient données × nombre de snapshots.
-Hne voit que les liens internes au transfert. Les snapshots doivent être copiés ensemble, dans une seule commande rsync.dusur la source ne révèle pas le problème. Il compte un fichier multi-lié une seule fois ; c’est sur la destination que l’espace explose.- Le meilleur snapshot est parfois celui qu’on supprime. Un miroir unique est plus simple à copier, à purger et à vérifier que des dossiers datés dont personne ne se sert.