ZFS zfs send : Le moyen le plus rapide pour transférer des téraoctets (si vous le faites bien)

Cet article vous a aidé ?

Il existe deux types de migrations de données : celles que vous planifiez, et celles que vous effectuez pendant que tout le monde regarde. ZFS zfs send/zfs receive est l’un des rares outils capables de gérer les deux—transférer des téraoctets avec intégrité, reproductibilité et un modèle clair de ce qui a changé. Mais c’est aussi l’un des moyens les plus simples de produire un transfert « réussi » qui est subtilement incorrect, douloureusement lent ou impossible à reprendre.

Voici un guide de terrain issu de la production : comment répliquer rapidement, comment savoir ce qui se passe réellement, ce qui casse sous pression, et quelles pratiques ennuyeuses vous évitent de devenir l’exemple cité lors du postmortem du trimestre prochain.

Pourquoi zfs send est différent (et pourquoi ça compte)

La plupart des « outils de copie » déplacent des fichiers. ZFS déplace la vérité : une vue cohérente à un instant T d’un dataset représentée par un snapshot. Un flux zfs send n’est pas « ce qu’il y avait dans le répertoire pendant qu’rsync tournait ». C’est « exactement les blocs référencés par le snapshot X », éventuellement plus « exactement les blocs modifiés de X à Y ». Cette différence explique pourquoi la réplication ZFS peut être à la fois plus rapide et plus correcte que la migration au niveau fichier.

Le compromis est que vous devez respecter le modèle de ZFS. Si vous ne le faites pas, vous finirez par tenter de répliquer une cible en mouvement, répliquer depuis une base incorrecte, ou répliquer des données chiffrées d’une manière qui semble correcte jusqu’au jour de la restauration. Dans l’univers ZFS, une migration est une chaîne de snapshots et d’hypothèses. Votre travail est de garder la chaîne intacte et les hypothèses explicites.

Une blague, pour donner le ton : la réplication ZFS, c’est comme déménager une maison en expédiant la fondation — efficace et cohérente, mais vous devriez probablement mesurer l’allée d’abord.

Faits intéressants et contexte historique

  • ZFS a été conçu pour l’intégrité de bout en bout : les checksums sont validés à la lecture, ce qui signifie que réplication + scrub vous donne une histoire de détection de corruption que la plupart des outils fichiers ne peuvent pas égaler.
  • Les snapshots sont volontairement peu coûteux : les snapshots ZFS sont des références copy-on-write, pas des copies complètes, rendant la réplication incrémentielle pratique à grande échelle.
  • Les flux de send sont déterministes : donné le même dataset/snapshot, le flux est suffisamment stable pour supporter la reprise et des receives fiables.
  • Le send incrémentiel est une fonctionnalité de première classe : ce n’est pas « diff des fichiers », c’est l’envoi uniquement des blocs changés entre snapshots.
  • Les datasets chiffrés ont changé la donne : les envois « raw » vous permettent de répliquer des données chiffrées sans exposer le texte clair sur le réseau ni sur le récepteur.
  • La gestion des propriétés côté receive est volontaire : ZFS vous donne des réglages pour remplacer les mountpoints, prévenir les montages automatiques surprenants, et gérer les propriétés séparément des données.
  • Les tokens de reprise ont été ajoutés parce que les réseaux mentent : les longs flux sur des liens instables avaient besoin d’un mécanisme officiel et sûr de reprise plutôt que de « recommencer et espérer ».
  • La réplication ZFS est utilisée comme PRA économique (et souvent efficace) : parce qu’elle peut être planifiée, incrémentielle et vérifiable, beaucoup d’organisations construisent leur PRA dessus avant d’acheter des solutions plus sophistiquées.

Modèle mental : snapshots, flux et confiance

1) Vous ne répliquez pas « un dataset », vous répliquez « un graphe de snapshots »

Les datasets ZFS ont un état qui change constamment. Les snapshots figent cet état. Un flux send référence des snapshots. Les envois incrémentiels référencent des paires de snapshots : une base et une cible.

Implication pratique : si le snapshot de base manque sur le récepteur, un receive incrémentiel ne peut pas s’appliquer. Si quelqu’un supprime des « vieux snapshots inutiles » sur la destination, vous venez de casser la réplication de demain. Ce n’est pas un cas théorique ; c’est un motif d’incident récurrent.

2) « Full » vs « incrémentiel » n’est pas une question de taille, mais de lignée

Un envoi complet (zfs send pool/ds@snap) fournit l’état entier du dataset à ce snapshot. Un envoi incrémentiel (-i ou -I) suppose que le récepteur dispose déjà d’un snapshot apparenté.

  • -i envoie les changements d’un snapshot précis à un autre (« de A à B »).
  • -I envoie une chaîne incrémentielle incluant les snapshots intermédiaires (« de A jusqu’à B, y compris les snapshots intermédiaires »).

3) Votre véritable ennemi n’est pas la vitesse — c’est la divergence silencieuse

La vitesse est facile à obsessionner parce qu’elle est visible. La divergence est ce qui gâche votre week-end : un receive qui « a marché » mais qui a monté au mauvais emplacement ; un dataset reçu avec des propriétés qui changent la sémantique applicative ; un dataset chiffré reçu d’une manière qui rend les clés et les clones pénibles plus tard.

4) Les flux contiennent plus que le contenu des fichiers

Les flux ZFS peuvent inclure les propriétés, les snapshots, les clones (avec les bons flags) et — en mode raw — les métadonnées de chiffrement. C’est puissant. C’est aussi une source d’erreurs si vous ne décidez pas intentionnellement quoi préserver.

Tâches pratiques (commandes + interprétation)

Les commandes ci-dessous supposent un hôte source (src) et un hôte destination (dst) avec des pools ZFS déjà créés. Remplacez les noms de pool et de dataset en conséquence. Les sorties sont représentatives ; votre système variera.

Tâche 1 : Confirmer la santé du pool avant la réplication

cr0x@src:~$ zpool status
  pool: tank
 state: ONLINE
status: Some supported features are not enabled on the pool.
action: Enable all features using 'zpool upgrade'. Once this is done,
        the pool may no longer be accessible by software that does not support the features.
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0

errors: No known data errors

Interprétation : Si vous voyez DEGRADED, un resilvering ou des erreurs de checksum, corrigez cela d’abord. La réplication transfert fidèlement la corruption aussi ; les checksums ZFS la détectent, mais ils ne guérissent pas magiquement la source.

Tâche 2 : Estimer la taille du dataset et l’empreinte des snapshots

cr0x@src:~$ zfs list -o name,used,avail,refer,mountpoint -r tank/prod
NAME           USED  AVAIL  REFER  MOUNTPOINT
tank/prod      8.2T  12.1T   128K  /tank/prod
tank/prod/db   6.9T  12.1T   6.9T  /tank/prod/db
tank/prod/log  1.3T  12.1T   1.3T  /tank/prod/log

Interprétation : USED inclut les snapshots et les descendants. REFER est la donnée référencée par le dataset lui‑même. Si USED est bien plus grand que REFER, vous avez une rétention significative de snapshots ; la réplication incrémentielle sera votre amie.

Tâche 3 : Créer un snapshot de réplication avec une convention de nommage

cr0x@src:~$ zfs snapshot -r tank/prod@replica-2025-12-25-0001

Interprétation : Utilisez un préfixe de snapshot prévisible (replica-) afin de pouvoir automatiser la sélection et la rétention sans toucher aux snapshots créés manuellement.

Tâche 4 : Estimation sèche de la taille du send (pour planifier)

cr0x@src:~$ zfs send -nP -R tank/prod@replica-2025-12-25-0001
size	9.11T

Interprétation : -nP estime la taille sans envoyer. -R réplique le dataset plus ses descendants et propriétés. L’estimation vous aide à décider si vous avez besoin d’incrémentiels, de compression ou d’une fenêtre de maintenance.

Tâche 5 : Faire la première réplication complète (options sûres)

cr0x@src:~$ zfs send -R tank/prod@replica-2025-12-25-0001 | ssh dst sudo zfs receive -u -o mountpoint=/tank/restore tank/recv

Interprétation : -u empêche le montage immédiat sur la destination, évitant des montages surprises sur des systèmes en production. Remplacer le mountpoint garantit que vous ne montez pas accidentellement sur des chemins de production. Recevoir dans tank/recv crée un espace de noms propre ; vous pouvez ensuite promouvoir ou renommer.

Tâche 6 : Vérifier que les snapshots reçus existent et correspondent aux noms

cr0x@dst:~$ zfs list -t snapshot -r tank/recv | head
NAME                                              USED  AVAIL  REFER  MOUNTPOINT
tank/recv/prod@replica-2025-12-25-0001             0B      -   6.9T  -
tank/recv/prod/db@replica-2025-12-25-0001          0B      -   6.9T  -
tank/recv/prod/log@replica-2025-12-25-0001         0B      -   1.3T  -

Interprétation : La présence des snapshots est votre preuve de lignée. Si vous ne voyez pas le snapshot attendu, ne passez pas aux incrémentiels tant que vous n’avez pas compris pourquoi.

Tâche 7 : Lancer un envoi incrémentiel (étape unique)

cr0x@src:~$ zfs snapshot -r tank/prod@replica-2025-12-25-0600
cr0x@src:~$ zfs send -R -i tank/prod@replica-2025-12-25-0001 tank/prod@replica-2025-12-25-0600 | ssh dst sudo zfs receive -u tank/recv

Interprétation : Cela n’envoie que les blocs modifiés entre ces deux snapshots, mais utilise toujours -R pour couvrir les descendants. L’opération échouera si la destination n’a pas le snapshot de base.

Tâche 8 : Incrémentiel avec intermédiaires (-I) pour les runs manqués

cr0x@src:~$ zfs send -R -I tank/prod@replica-2025-12-25-0001 tank/prod@replica-2025-12-25-1800 | ssh dst sudo zfs receive -u tank/recv

Interprétation : Si votre job de réplication a manqué plusieurs snapshots, -I peut envoyer une chaîne incluant les snapshots intermédiaires — ce qui facilite souvent la rétention et le rollback sur la destination.

Tâche 9 : Envoyer avec compression sur le lien (pragmatique)

cr0x@src:~$ zfs send -R tank/prod@replica-2025-12-25-0001 | gzip -1 | ssh dst "gunzip | sudo zfs receive -u tank/recv"

Interprétation : C’est simple et souvent efficace sur des datasets riches en logs ou en texte. Sur des données déjà compressées (sauvegardes, médias), cela peut gaspiller du CPU pour peu de bénéfice. Mesurez, ne devinez pas.

Tâche 10 : Répliquer un dataset chiffré en toute sécurité (raw send)

cr0x@src:~$ zfs get -o name,property,value -s local encryptionroot,keystatus -r tank/secure
NAME         PROPERTY      VALUE
tank/secure  encryptionroot  tank/secure
tank/secure  keystatus       available

cr0x@src:~$ zfs snapshot -r tank/secure@replica-0001
cr0x@src:~$ zfs send -w -R tank/secure@replica-0001 | ssh dst sudo zfs receive -u tank/recv-secure

Interprétation : -w envoie le flux chiffré brut. La destination reçoit des blocs chiffrés ; vous n’exposez pas le texte clair pendant le transfert. C’est souvent ce que demandent les équipes sécurité, à condition d’avoir un plan de gestion des clés sur le récepteur.

Tâche 11 : Gérer une interruption avec des tokens de reprise (ne pas tout recommencer)

cr0x@dst:~$ zfs get -H -o value receive_resume_token tank/recv/prod
1-ED8f3a9c0c-...

cr0x@src:~$ zfs send -t 1-ED8f3a9c0c-... | ssh dst sudo zfs receive -u tank/recv

Interprétation : Si un receive a été interrompu, ZFS peut stocker un token de reprise sur le dataset destination. Envoyer avec -t continue là où il s’était arrêté, à condition que le token soit valide et que le flux corresponde. Cette fonctionnalité fait la différence entre « on a perdu le lien 30 secondes » et « on renvoie 40 To ».

Tâche 12 : Éviter le chaos de mountpoint accidentel au receive

cr0x@dst:~$ sudo zfs receive -u -o mountpoint=/mnt/quarantine -o canmount=off tank/recv < /tmp/stream.zfs

Interprétation : Si vous recevez depuis un fichier ou une zone de staging, forcer canmount=off et un mountpoint de quarantaine empêche les montages inattendus, surtout lorsque -R apporte plusieurs descendants avec des propriétés héritées.

Tâche 13 : Confirmer que la destination lit réellement des données saines

cr0x@dst:~$ zpool scrub tank
cr0x@dst:~$ zpool status tank
  pool: tank
 state: ONLINE
status: Scrub in progress since Thu Dec 25 09:10:52 2025
        1.23T scanned at 6.10G/s, 180G issued at 900M/s, 9.11T total
        0B repaired, 1.98% done, 0:28:10 to go
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
errors: No known data errors

Interprétation : Un scrub après un receive majeur n’est pas de la paranoïa ; c’est de la validation. Si votre copie PRA est corrompue, vous voulez le savoir maintenant, pas lors d’une panne.

Tâche 14 : Mesurer la performance send/receive sans supposition

cr0x@src:~$ zfs send -nP tank/prod@replica-2025-12-25-0001
size	9.11T

cr0x@src:~$ time zfs send -R tank/prod@replica-2025-12-25-0001 | ssh dst sudo zfs receive -u tank/recv
real	154m12.331s
user	2m10.912s
sys	12m48.776s

Interprétation : La sortie de time plus l’estimation de taille vous permet de calculer le débit effectif. N’optimisez pas à l’aveugle : si le temps CPU est bas mais le temps réel énorme, vous attendez le réseau ou les disques.

Performance : comment le rendre réellement rapide

« Le moyen le plus rapide pour transférer des téraoctets » est vrai, mais sous conditions. ZFS peut pousser les données au débit maximal quand les étoiles s’alignent : lectures séquentielles-ish, surcharge CPU minimale, un pool récepteur capable d’ingérer les écritures, et un réseau qui ne fond pas au moindre éternuement. Dans la vraie vie, l’un d’eux est toujours le goulot d’étranglement.

Commencez par la contrainte ennuyeuse : la réplication est un pipeline

Un send/receive est un pipeline : lecture pool source → création du flux send → transport (souvent SSH) → parsing du flux receive → écriture pool destination → montage optionnel et post-traitement. Le pipeline fonctionne à la vitesse de l’étape la plus lente. Votre travail est d’identifier rapidement cette étape et soit de la supprimer soit de l’accepter.

SSH : pratique, sécurisé, et parfois votre goulot

SSH est le transport par défaut parce qu’il est omniprésent et sécurisé par défaut. Mais le chiffrement peut devenir le plafond sur des liens rapides. Si vous transférez des dizaines de téraoctets sur 10/25/40/100GbE, testez la marge CPU pour le chiffrement SSH. Si les CPU sont saturés, vous avez des options :

  • Choisir des chiffres pris en charge par l’accélération matérielle sur vos CPU (souvent AES-GCM sur les x86 modernes).
  • Paralléliser en scindant les datasets (plusieurs sends indépendants) si votre stockage peut le supporter.
  • Utiliser des sends raw pour les datasets chiffrés (toujours chiffrés au niveau ZFS), mais vous avez toujours le chiffrement SSH à moins de changer le transport.

Deuxième blague, puis on retourne au travail : La seule chose plus rapide qu’un lien 100Gb saturé est un ingénieur qui dit « c’est probablement le DNS » alors que c’est manifestement le CPU.

Compression : un levier, pas une religion

La compression en transit peut être magique sur des bases de données riches en écritures et contenant beaucoup de zéros ou de motifs répétitifs, et un total gaspillage sur les JPEG et Parquet. Utilisez zfs send -nP pour dimensionner, puis faites un court échantillon chronométré (petit dataset ou incrément récent) avec et sans compression. Décidez sur la base du débit mesuré et de la consommation CPU, pas des impressions.

Recordsize, volblocksize, et pourquoi les bases de données se comportent différemment

Le recordsize d’un dataset ZFS impacte la disposition des données et peut influencer indirectement le comportement du send. Les bases qui font beaucoup de petits writes aléatoires bénéficient souvent de blocs plus petits (ou de datasets séparés), mais la réplication reste basée sur les blocs. Pour les zvols (périphériques bloc), le volblocksize est fixe à la création ; si vous répliquez de grands zvols avec un petit volblocksize, vous vous inscrivez pour plus de métadonnées et potentiellement un débit inférieur.

L’ingestion par le pool destination : le tueur silencieux

Vous pouvez avoir une source et un réseau ultra rapides, et pourtant ramper parce que le pool de destination ne peut pas engager les écritures. Raisons courantes :

  • SLOG petit ou mal configuré (pour les écritures sync sur certains workloads ; receive n’est pas purement sync mais peut être affecté par le comportement du pool).
  • Disques rotatifs avec une largeur de vdev insuffisante pour un ingéré soutenu.
  • Mauvais ashift, disques défaillants, ou un pool déjà occupé par d’autres charges.
  • Pression mémoire provoquant un mauvais comportement de l’ARC et des IO supplémentaires.

Utilisez des receives de staging quand il faut protéger la production

Pattern courant : recevoir dans pool/recv avec canmount=off et un mountpoint sûr, puis faire une bascule contrôlée : renommer les datasets, définir les mountpoints, charger les clés, monter et démarrer les services. Cela ne rend pas le transfert plus rapide, mais le rend survivable.

Trois mini-histoires du monde de l’entreprise

Mini-histoire n°1 : L’incident causé par une mauvaise hypothèse

Le plan de migration semblait propre : réplication complète le vendredi soir, incrémentiels toutes les heures, bascule dimanche. L’équipe a supposé que « incrémentiel » signifiait « la destination a juste besoin du nom du dataset ». Ce n’était pas le cas. Elle avait besoin du snapshot de base exact.

Le samedi matin, quelqu’un a fait du ménage sur la destination parce qu’elle « avait trop de snapshots ». Ils ont supprimé un snapshot vieux d’une semaine qui ne correspondait pas au schéma de nommage replica- — parce qu’il ne correspondait pas. C’était un snapshot automatique d’un test antérieur, et il s’est avéré être la base incrémentielle utilisée par le job depuis vendredi.

À 10h00, l’incrémentiel horaire a commencé à échouer avec un message qui ressemblait à un problème transitoire de receive. Le runbook disait « retry », alors il a retenté. Puis il a retenté encore. Pendant ce temps, de nouvelles écritures continuaient sur la source, élargissant l’écart.

Quand quelqu’un a finalement remarqué que le motif d’erreurs était cohérent, l’équipe faisait face à un choix désagréable : re-seeder un envoi complet de plusieurs téraoctets pendant les heures ouvrées ou accepter une fenêtre d’indisponibilité plus longue. Ils ont re-seedé la nuit et effectué la bascule tard. Personne n’a été viré, mais la pipeline de réplication a reçu une nouvelle règle : le snapshot de base est sacré, et les politiques de rétention doivent être automatisées et sensibles au préfixe.

Leçon : La réplication incrémentielle concerne la lignée des snapshots, pas « l’état le plus récent ». Si la destination perd la base, vous n’avez pas de réplication — vous avez une bombe à retardement.

Mini-histoire n°2 : L’optimisation qui a mal tourné

Une autre équipe voulait de la vitesse. Ils avaient un lien 40Gb et un arriéré de datasets à répliquer vers un site PRA. Quelqu’un a suggéré de tout compresser « parce que c’est toujours plus rapide ». Ils ont enveloppé zfs send dans une compression agressive et ont déclaré victoire après un test sur un dataset textuel.

Puis ils l’ont appliqué à des archives média et des images VM. Le CPU est monté au plafond sur les deux bouts, les threads SSH se disputaient les cycles, et le débit a chuté en dessous de ce que le flux non compressé aurait pu faire. Pire : le receive a commencé à prendre du retard au point de déclencher du bruit opérationnel — timeouts, alertes de monitoring, et une cascade de messages « le site PRA est-il en panne ? »

La correction n’a pas été héroïque. Ils ont lancé un court benchmark par classe de dataset et défini une politique : compresser sur le réseau pour les logs et les dumps de bases ; ne pas compresser pour les blobs déjà compressés ; préférer les sends raw pour les datasets chiffrés ; et limiter la concurrence basée sur la capacité d’écriture du pool destination, pas sur la vitesse réseau. La pipeline est devenue stable et prévisible — moins excitante, plus efficace.

Leçon : Optimiser une étape du pipeline peut affamer une autre. La compression est un échange débit vs CPU : réseau sauvé, CPU dépensé. Dépensez le CPU seulement quand il vous fait réellement gagner du temps.

Mini-histoire n°3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

La meilleure histoire de réplication que je peux raconter est celle où rien ne s’est passé. Une équipe stockage avait une routine : avant tout receive majeur, ils utilisaient -u pour empêcher les montages, forçaient un mountpoint de quarantaine, et lançaient un scrub dans les 24 heures. Ils étiquetaient aussi les snapshots de réplication avec un préfixe strict et refusaient tout « nettoyage manuel de snapshots » sur la destination.

Un trimestre, le site PRA a subi un événement d’alimentation chaotique. La plupart des systèmes sont revenus, mais une baie de disques avait un problème de contrôleur provoquant des erreurs IO intermittentes. Le pool est resté en ligne, mais il n’était pas heureux. Le job de réplication a continué et a signalé un succès pour certains datasets — jusqu’à ce que le scrub détecte des erreurs de checksum sur des blocs récemment reçus.

Parce qu’ils scrubaient régulièrement, ils ont détecté le problème avant une vraie catastrophe. Ils ont suspendu la réplication, réparé le matériel, renvoyé les incrémentiels affectés en respectant la lignée sauvegardée des snapshots, et validé à nouveau. Quand un incident de production non lié est survenu des semaines plus tard, la copie PRA était réellement utilisable — parce que l’équipe considérait la « validation » comme faisant partie de la réplication, pas comme un luxe.

Leçon : Les pratiques ennuyeuses — pas de montages automatiques, nommage cohérent des snapshots, scrubs périodiques — ne sont pas de la cérémonie. Ce sont la différence entre une PRA sur une présentation et une PRA utilisable.

Playbook de diagnostic rapide

Quand une réplication est lente ou échoue, vous n’avez pas de temps pour une danse interprétative. Voici la route la plus rapide vers le goulot, dans l’ordre qui paye généralement.

Première étape : confirmer qu’il y a réellement du progrès (et pas des retries)

cr0x@dst:~$ ps aux | egrep 'zfs receive|ssh' | grep -v egrep
root     21844  2.1  0.1  24548  9120 ?        Ss   09:20   0:01 zfs receive -u tank/recv
root     21843  0.9  0.0  16720  6340 ?        Ss   09:20   0:00 ssh -oBatchMode=yes src zfs send -R tank/prod@replica-2025-12-25-0600

Interprétation : Si vous voyez des processus de courte durée répétés, vous êtes en train de flapper à cause d’une erreur. Si les processus sont de longue durée, vous êtes probablement lent, pas en échec.

Deuxième étape : vérifier si la destination est le goulot (pool occupé ou en mauvaise santé)

cr0x@dst:~$ zpool iostat -v tank 2 3
                                              capacity     operations     bandwidth
pool                                        alloc   free   read  write   read  write
------------------------------------------  -----  -----  -----  -----  -----  -----
tank                                        9.40T  8.90T     10    980   12M   820M
  mirror-0                                  9.40T  8.90T     10    980   12M   820M
    sda                                         -      -      5    490    6M   410M
    sdb                                         -      -      5    490    6M   410M
------------------------------------------  -----  -----  -----  -----  -----  -----

Interprétation : Si les écritures sont proches du plafond physique du pool, c’est votre goulot. Si les écritures sont faibles mais que le send est lent, regardez ailleurs (CPU SSH, lectures source, réseau).

Troisième étape : vérifier la saturation CPU liée à SSH

cr0x@src:~$ top -b -n 1 | head -n 15
top - 09:24:11 up 31 days,  6:02,  2 users,  load average: 18.22, 16.91, 14.77
Tasks: 312 total,   2 running, 310 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.2 us,  1.1 sy,  0.0 ni,  7.4 id, 88.0 wa,  0.0 hi,  0.3 si,  0.0 st
MiB Mem : 257982.3 total,  11230.5 free,  78112.9 used, 170638.9 buff/cache

Interprétation : Un wa élevé signifie attente IO (lectures source probablement goulot). Un user/system élevé avec des processus ssh en tête suggère un overhead crypto.

Quatrième étape : vérifier les erreurs de lignée des snapshots (la classe « ça a échoué instantanément »)

cr0x@dst:~$ sudo zfs receive -u tank/recv
cannot receive incremental stream: destination tank/recv/prod has been modified

Interprétation : Cela signifie généralement que le dataset destination a divergé (des écritures ont eu lieu, des snapshots ont été supprimés, ou vous avez reçu au mauvais endroit). Corrigez la lignée, ne forcez pas des retries aveuglément.

Cinquième étape : vérifier si un décalage de mode de chiffrement vous bloque

cr0x@dst:~$ zfs get -o name,property,value -r tank/recv-secure | egrep 'encryptionroot|keystatus'
tank/recv-secure/secure  encryptionroot  tank/recv-secure/secure
tank/recv-secure/secure  keystatus       unavailable

Interprétation : keystatus unavailable est normal si les clés ne sont pas chargées. Cela devient problématique si votre workflow s’attend à un montage immédiat. Décidez si vous voulez une réplication raw (clés gérées séparément) ou une réplication déchiffrée (clés chargées à la source et données envoyées en clair dans le flux ZFS).

Erreurs courantes (symptômes + corrections)

Erreur 1 : Recevoir dans le mauvais chemin de dataset

Symptôme : Le receive se termine, mais les datasets apparaissent sous une hiérarchie inattendue (ou écrasent un dataset de test).

Correction : Toujours stage les receives dans un namespace clairement nommé (par ex. tank/recv) et utiliser -u. Vérifiez avec zfs list -r avant de monter ou renommer.

Erreur 2 : Supprimer des snapshots sur la destination « pour économiser de l’espace »

Symptôme : Les receives incrémentiels échouent avec « missing snapshot » ou « destination has been modified ».

Correction : La rétention doit être pilotée par une politique aware-réplication. Supprimez les snapshots de réplication uniquement selon un calendrier qui préserve la base requise pour le prochain incrémentiel.

Erreur 3 : Ne pas utiliser -u et subir des montages surprises

Symptôme : Après le receive, de nouveaux filesystems se montent automatiquement, parfois sur des chemins utilisés par des services de production.

Correction : Utilisez zfs receive -u et remplacez le mountpoint et/ou définissez canmount=off pendant le receive. Montez intentionnellement plus tard.

Erreur 4 : Supposer que la compression aide toujours

Symptôme : CPU saturé, débit pire que prévu, receive en retard.

Correction : Benchmarkez. Utilisez la compression seulement quand les données sont compressibles. Envisagez des niveaux de compression plus légers si le CPU est la limite.

Erreur 5 : Ignorer les feature flags du pool et la compatibilité de version

Symptôme : Le receive échoue sur des systèmes plus anciens, ou le pool répliqué ne peut pas être importé là où vous en avez besoin.

Correction : Alignez les versions/features ZFS entre sites avant de bâtir des hypothèses PRA. Si vous devez interopérer avec un ZFS plus ancien, évitez d’activer des features qui brisent la compatibilité.

Erreur 6 : Oublier que -R apporte propriétés et descendants

Symptôme : Des mountpoints, quotas, réservations ou autres propriétés apparaissent de manière inattendue sur la destination.

Correction : Utilisez des overrides -o côté receive quand c’est approprié, et auditez les propriétés critiques après receive avec zfs get. Maintenez un « contrat de propriétés » pour les datasets répliqués.

Erreur 7 : Ne pas planifier la reprise

Symptôme : Une coupure réseau transitoire force une retransmission complète et fait sauter la fenêtre.

Correction : Utilisez les tokens de reprise ZFS là où ils sont supportés. Concevez les jobs pour détecter les tokens et reprendre automatiquement plutôt que de tout relancer.

Checklists / plan pas à pas

Checklist A : Semis initial (full replication) qui ne vous fera pas de mal plus tard

  1. Vérifier la santé du pool sur les deux côtés (zpool status), corriger les erreurs d’abord.
  2. Choisir une convention de nommage pour les snapshots de réplication (replica-YYYY-MM-DD-HHMM).
  3. Créer un snapshot récursif sur la source pour le semis initial.
  4. Estimer la taille avec zfs send -nP -R pour comprendre le temps et la bande passante nécessaires.
  5. Recevoir dans un namespace de staging avec -u et des propriétés sûres (mountpoint/canmount).
  6. Vérifier que les snapshots existent sur la destination et que l’arbre des datasets correspond aux attentes.
  7. Scrubber le pool destination dans les 24 heures du semis pour avoir confiance.

Checklist B : Réplication incrémentielle continue (le mode quotidien)

  1. Créer de nouveaux snapshots selon un calendrier (horaire/quotidien), toujours avec le préfixe de réplication.
  2. Envoyer des incrémentiels en utilisant un snapshot de base connu ; préférer -I si vous voulez inclure les snapshots intermédiaires.
  3. Utiliser -u pour garder les receives non disruptifs ; ne monter qu’en bascules contrôlées ou tests.
  4. Surveiller les tokens de reprise et reprendre automatiquement si un job est interrompu.
  5. Appliquer des politiques de rétention aux snapshots de réplication sur les deux côtés, en préservant la lignée pour l’incrément suivant.

Checklist C : Plan de bascule (car « on va juste switcher » n’est pas un plan)

  1. Quiescer les écritures applicatives (mode maintenance, flush de la base, arrêt du service — ce qui est correct pour votre workload).
  2. Prendre des snapshots finaux et lancer un dernier envoi incrémentiel.
  3. Sur la destination : définir les mountpoints finaux, charger les clés de chiffrement si besoin, et valider l’existence des datasets.
  4. Monter les datasets et démarrer les services ; valider avec des contrôles applicatifs, pas seulement des montages filesystem.
  5. Garder la source en lecture seule et conserver les snapshots jusqu’à être confiant dans le nouvel état.

FAQ

1) Est-ce que zfs send | zfs receive est toujours plus rapide que rsync ?

Non, mais souvent il est plus rapide à grande échelle et généralement plus cohérent. Il excelle lorsque vous pouvez utiliser des incrémentiels et quand les sémantiques filesystem (permissions, hardlinks, xattrs) comptent. Si vous n’avez besoin que d’un petit sous-ensemble de fichiers ou si vous ne pouvez pas utiliser de snapshots, rsync peut être plus simple.

2) Dois-je toujours utiliser -R ?

Pas toujours. -R est excellent pour répliquer un arbre de dataset avec propriétés et snapshots. Si vous n’avez besoin que d’un dataset sans descendants ou si vous voulez un contrôle plus fin sur les propriétés qui voyagent, un send non récursif peut être plus sûr.

3) Quelle est la différence entre -i et -I déjà ?

-i envoie d’un snapshot à un autre (un seul delta). -I envoie une chaîne incrémentielle et inclut les snapshots intermédiaires entre la base et la cible. Utilisez -I quand vous voulez que la destination conserve le même historique de snapshots.

4) Comment savoir quel snapshot utiliser comme base incrémentielle ?

Utilisez le snapshot de réplication le plus récent qui existe à la fois sur la source et sur la destination. Opérationnellement, cela signifie : le dernier snapshot reçu avec succès portant votre préfixe de réplication. Ne devinez pas — listez les snapshots des deux côtés et faites correspondre les noms.

5) Puis-je reprendre un transfert interrompu en toute sécurité ?

Oui, si votre ZFS supporte les tokens de reprise et que vous n’avez pas détruit l’état de receive partiel. Vérifiez receive_resume_token sur le dataset destination ; s’il est présent, envoyez avec zfs send -t <token> et recevez à nouveau.

6) Est-ce que raw send (-w) signifie que les données restent chiffrées en transit ?

Le raw send signifie que ZFS envoie des blocs chiffrés et les métadonnées de chiffrement, donc le flux ZFS ne contient pas de texte clair. Beaucoup utilisent encore SSH, qui chiffre aussi le transport — c’est correct, mais pas requis pour la confidentialité quand le flux lui‑même est raw-encrypté.

7) Pourquoi mon receive incrémentiel a-t-il échoué avec « destination has been modified » ?

Parce qu’il l’a été. Cela peut signifier des écritures réelles sur le dataset destination, un rollback, un changement de propriété qui implique une divergence dans certains contextes, ou des snapshots manquants dans la lignée attendue. La correction consiste à rétablir une base commune — parfois via un rollback ou en effectuant un nouveau full send.

8) Comment empêcher que les datasets répliqués se montent automatiquement ?

Utilisez zfs receive -u. Pour plus de sécurité, définissez canmount=off et un mountpoint de quarantaine pendant le receive, puis modifiez les propriétés et montez intentionnellement plus tard.

9) Est-il sûr de répliquer des bases de données de production avec des snapshots ZFS ?

C’est sûr pour la consistance du filesystem, pas automatiquement pour la consistance applicative. Pour les bases de données, coordonnez les snapshots avec le mécanisme de consistance de la base (flush/checkpoint/mode backup) si vous avez besoin de garanties de consistance crash-consistent vs application-consistent.

10) Comment valider que la copie PRA est utilisable ?

Au minimum : assurez-vous que les snapshots sont présents, lancez des scrubs périodiques, et effectuez des restaurations tests ou des montages dans un environnement isolé. Un plan PRA sans exercices de restauration est juste une jolie histoire.

Conclusion

zfs send/zfs receive est l’un des rares outils capables de déplacer des téraoctets rapidement sans transformer la correction en exercice de foi. Mais ZFS est exigeant comme le sont les bons systèmes : la lignée des snapshots compte, les propriétés comptent, et le récepteur n’est pas une poubelle dans laquelle on verse des flux.

Si vous le voulez rapide, traitez la réplication comme un pipeline et mesurez où vous êtes throttlé. Si vous le voulez fiable, considérez le nommage des snapshots, la rétention, le comportement de reprise et la validation post-receive comme faisant partie du système — pas des extras optionnels. Faites‑le bien et vous obtiendrez quelque chose de rare : une vitesse sur laquelle vous pouvez compter.

← Précédent
OpenVPN sur Windows : problèmes du pilote TAP et comment les réparer
Suivant →
Tailscale : VPN sans douleur et les erreurs d’accès qui font encore mal

Laisser un commentaire