Votre tableau de bord de sauvegarde est vert. Vos snapshots sont « en cours ». Vos auditeurs sont rassurés.
Puis survient un incident réel—rançongiciel, rm -rf accidentel, un contrôleur qui meurt, ou quelqu’un qui « aide » en détruisant un dataset—et tout à coup vous apprenez en direct ce que signifie vraiment « restauration ».
Un exercice DR ZFS send/receive, c’est l’endroit où vous échangez la théorie rassurante contre la réalité mesurée : combien de temps ça prend, ce qui casse, ce qui manque, et ce que vous auriez aimé tester le trimestre dernier.
Les sauvegardes sont un processus. La restauration est une performance.
Pourquoi les exercices DR ZFS sont importants (et ce qu’ils testent vraiment)
La réplication ZFS send/receive est séduisante parce qu’elle paraît déterministe : le snapshot A part, le snapshot A arrive, et vous pouvez même mesurer les octets en transit.
Cela encourage une habitude dangereuse : confondre réplication et récupération.
Un exercice DR n’est pas « peut-on copier des données ». C’est « peut-on restaurer un service », avec tous les détails désagréables associés :
- Identité : les noms de datasets, les points de montage et les permissions sont-ils corrects sur la cible ?
- Dépendances : avez-vous aussi besoin des WAL PostgreSQL, de la config applicative, des secrets, des clés TLS ou des métadonnées de VM ?
- Temps : atteignez-vous réellement le RPO et le RTO lorsque le réseau est chargé et que l’astreinte est fatiguée ?
- Sécurité : pouvez-vous le faire sans écraser la dernière bonne copie ?
- Personnes : quelqu’un d’autre que « la personne ZFS » sait-il quoi taper ?
Vous ne lancez pas d’exercices DR pour prouver que ZFS fonctionne. ZFS fonctionne. Vous les lancez pour attraper les parties qui ne fonctionnent pas : vos hypothèses, votre automatisation, la gestion des clés,
vos conventions de nommage, et votre habitude de ne pas noter la chose étrange que vous avez faite il y a trois ans à 2 h du matin.
Une citation opérationnelle qui a bien vieilli : L’espoir n’est pas une stratégie.
— James Cameron.
Elle s’applique aux restaurations de sauvegarde avec une précision embarrassante.
Blague n°1 : Les sauvegardes sont comme les parachutes—si vous n’en avez pas testé un, vous allez apprendre beaucoup très vite.
Faits intéressants et brève histoire
Un peu de contexte aide parce que ZFS send/receive n’est pas « une copie de fichiers ». C’est un flux d’état du système de fichiers, et les choix de conception derrière expliquent
beaucoup des aspérités que vous rencontrerez dans les exercices.
- La réplication par snapshot précède la mode cloud : send/receive existe depuis les débuts de ZFS, conçu pour des flux de réplication d’entreprise réels.
- Les flux ZFS sont transactionnels : vous envoyez des blocs et des métadonnées du dataset à l’état d’un snapshot, pas des « changements de fichiers » comme rsync.
- Les incrémentiels dépendent de la lignée : un flux incrémentiel exige que le récepteur possède le snapshot de base exact (même GUID), pas seulement un snapshot portant le même nom.
- Les propriétés se transmettent (parfois) : avec
-pet les flags associés, les propriétés des datasets peuvent être répliquées, ce qui est soit une bénédiction soit une source de chaos selon vos conventions cibles. - Le chiffrement a changé la donne : le chiffrement natif ZFS a introduit des réalités de gestion de clés dans la réplication—en particulier les envois « raw » et le chargement des clés sur le récepteur.
- La compression n’est pas « du débit gratuit » : la taille du flux ZFS varie fortement selon recordsize, compressratio, et si vous envoyez des données compressées ou brutes.
- Le receive n’est pas toujours idempotent : des réceptions répétées peuvent échouer ou diverger si des snapshots ont été élagués, des retours arrière effectués, ou une réception précédente a laissé un état partiel.
- La réplication n’est pas la rétention de sauvegarde : send/receive reflète l’historique de snapshots que vous choisissez ; il ne résout pas automatiquement la rétention, le legal hold, ou les copies hors ligne.
- ZFS a toujours été axé sur l’intégrité : les checksums sont bout en bout, mais les exercices détectent encore les éléments du monde réel : mauvais câbles, RAM instable, arc mal dimensionné, ou pool cible submergé.
Définir l’exercice : périmètre, RPO/RTO et critère de « terminé »
Ne commencez pas par des commandes. Commencez par des définitions, car les exercices DR échouent le plus souvent en tant qu’échecs de gestion de projet déguisés en technique.
Définissez trois choses avant de toucher un shell :
1) Qu’est-ce que vous restaurez ?
Choisissez un service avec suffisamment de complexité pour être honnête : une appli web avec base de données, un partage de fichiers avec ACL, une charge de VM, ou une pipeline d’analytique.
Incluez « tout ce qui est nécessaire pour opérer » pour ce service, pas seulement son dataset principal.
2) Quel RPO et RTO allez-vous mesurer ?
- RPO : le snapshot le plus récent acceptable que vous pouvez restaurer (par ex., « pas plus de 15 minutes de perte de données »).
- RTO : le temps entre la déclaration du sinistre et le retour des utilisateurs en service (par ex., « moins de 2 heures »).
Pour la réplication ZFS, vous pouvez souvent contrôler le RPO avec la cadence des snapshots et la fréquence de réplication. Le RTO, c’est là où la réalité mord :
bande passante réseau, performance du pool cible, chargement des clés, ordre de montage, vérifications de service, DNS, et récupération au niveau applicatif.
3) À quoi ressemble « terminé » ?
« Dataset reçu avec succès » n’est pas « terminé ». « L’application passe les tests smoke » est plus proche.
Votre définition de terminé devrait inclure :
- Datasets montés comme prévu (ou intentionnellement non montés jusqu’au basculement).
- Services démarrés et sains.
- Permissions et propriété correctes.
- Au moins un chemin de lecture/écriture réel vérifié (connexion fonctionnelle, requête réussie, création de fichier fonctionnelle).
- Horodatages mesurés pour chaque phase (durée du receive, durée de montage, durée de récupération applicative).
Préparation : quoi construire avant de s’entraîner
Un exercice DR devrait sembler répété. Pas parce que c’est une pièce de théâtre, mais parce que quand c’est réel vous n’aurez pas le temps d’inventer la chorégraphie.
Construisez ces éléments à l’avance.
Noms qui ne vous feront pas mal plus tard
Décidez comment le côté DR nomme pools et datasets. Si vous répliquez tank/prod/app vers backup/prod/app, vous faites un choix sur
les points de montage, les attentes fstab, et les outils.
Je recommande de recevoir dans un pool et un namespace dédiés sur l’hôte DR, comme drpool/recv/prod/app, puis d’utiliser une promotion/renommage contrôlée au basculement.
Cela évite les montages accidentels sur des chemins de production pendant un exercice.
Gestion des clés (si vous utilisez le chiffrement natif)
Si vos datasets sont chiffrés, la réplication n’est pas juste « des données ». Ce sont des clés, des emplacements de clés, et qui peut les charger sous pression.
Décidez si l’hôte DR stocke les clés (plus risqué mais restauration plus rapide) ou exige un chargement manuel des clés (plus sûr mais plus lent).
Dans tous les cas, testez-le.
Automatisation ennuyeuse volontaire
L’automatisation DR devrait être volontairement monotone : noms de snapshots explicites, cibles de receive explicites, journalisation dans un fichier, et échec immédiat en cas d’incohérence.
Ne devenez pas malin avec une logique implicite « dernier snapshot » sauf si vous avez aussi des garde-fous.
Capacité et réalité de la fragmentation
La réplication ne vous sauvera pas d’un stockage DR sous-dimensionné. ZFS n’est pas impressionné par l’optimisme.
Dimensionnez le pool DR pour contenir : datasets répliqués, rétention de snapshots, et de l’espace pour que le receive respire (il faut de la marge).
Si vous êtes proche du plein, votre exercice devrait inclure le moment où le receive s’arrête en plein flux.
Tâches pratiques (commandes, sorties, décisions)
Ces tâches sont destinées à être exécutées pendant un exercice DR (ou pendant la préparation). Chacune inclut :
la commande, une sortie réaliste, ce que cela signifie, et la décision que vous en tirez.
Les noms d’hôtes et de pools sont des exemples : prod1 envoie depuis tank, dr1 reçoit dans drpool.
Tâche 1 : Confirmer la santé du pool avant de répliquer
cr0x@prod1:~$ zpool status -x
all pools are healthy
Ce que ça signifie : Pas d’erreurs vdev connues. C’est votre référence.
Décision : Si ce n’est pas sain, arrêtez. Ne répliquez pas de la corruption et appelez ça du DR.
Tâche 2 : Vérifier l’espace libre et la fragmentation (expéditeur et récepteur)
cr0x@prod1:~$ zpool list -o name,size,alloc,free,frag,cap,health
NAME SIZE ALLOC FREE FRAG CAP HEALTH
tank 7.25T 5.10T 2.15T 28% 70% ONLINE
cr0x@dr1:~$ zpool list -o name,size,alloc,free,frag,cap,health
NAME SIZE ALLOC FREE FRAG CAP HEALTH
drpool 9.06T 3.40T 5.66T 12% 37% ONLINE
Ce que ça signifie : Le récepteur a beaucoup d’espace libre ; la fragmentation est modérée.
Décision : Si CAP > 80% ou si la frag est élevée, attendez-vous à des receives plus lents et à un risque d’ENOSPC lors de la rétention des snapshots. Corrigez la capacité avant l’exercice.
Tâche 3 : Vérifier la liste des datasets et les propriétés critiques
cr0x@prod1:~$ zfs list -r -o name,used,avail,recordsize,compression,encryption,mountpoint tank/prod/app
NAME USED AVAIL RECORDSIZE COMPRESS ENCRYPTION MOUNTPOINT
tank/prod/app 820G 1.20T 128K zstd aes-256-gcm /srv/app
tank/prod/app/db 540G 1.20T 16K zstd aes-256-gcm /var/lib/postgresql
tank/prod/app/logs 120G 1.20T 128K zstd aes-256-gcm /srv/app/logs
Ce que ça signifie : Le recordsize diffère entre l’app et la DB, la compression est zstd, chiffrement activé.
Décision : Assurez-vous que la cible DR est compatible avec ces propriétés. Pour les exercices DR, évitez d’hériter aveuglément des points de montage qui pourraient entrer en collision avec des chemins locaux.
Tâche 4 : Confirmer la cadence des snapshots et le « point sûr le plus récent » (RPO)
cr0x@prod1:~$ zfs list -t snapshot -o name,creation -s creation -r tank/prod/app | tail -n 5
tank/prod/app@dr-2025-12-26_1000 Fri Dec 26 10:00 2025
tank/prod/app@dr-2025-12-26_1015 Fri Dec 26 10:15 2025
tank/prod/app@dr-2025-12-26_1030 Fri Dec 26 10:30 2025
tank/prod/app@dr-2025-12-26_1045 Fri Dec 26 10:45 2025
tank/prod/app@dr-2025-12-26_1100 Fri Dec 26 11:00 2025
Ce que ça signifie : Snapshots toutes les 15 minutes. Votre RPO est borné par ce planning plus le retard de réplication.
Décision : Si les snapshots ne sont pas réguliers, la réplication ne peut pas atteindre un RPO que vous n’avez pas conçu.
Tâche 5 : Mesurer le retard de réplication en comparant les derniers snapshots expéditeur vs récepteur
cr0x@dr1:~$ zfs list -t snapshot -o name,creation -s creation -r drpool/recv/prod/app | tail -n 3
drpool/recv/prod/app@dr-2025-12-26_1030 Fri Dec 26 10:30 2025
drpool/recv/prod/app@dr-2025-12-26_1045 Fri Dec 26 10:45 2025
drpool/recv/prod/app@dr-2025-12-26_1100 Fri Dec 26 11:00 2025
Ce que ça signifie : Le récepteur a le dernier snapshot. Le retard est pour l’instant nul.
Décision : Si le récepteur est en retard, décidez si votre exercice utilise le snapshot le plus récent reçu (réaliste) ou si vous arrêtez la production pour forcer l’alignement (moins réaliste).
Tâche 6 : Estimation en dry-run de la taille d’un send incrémentiel
cr0x@prod1:~$ zfs send -nPv -I tank/prod/app@dr-2025-12-26_1045 tank/prod/app@dr-2025-12-26_1100
send from @dr-2025-12-26_1045 to tank/prod/app@dr-2025-12-26_1100 estimated size is 14.2G
total estimated size is 14.2G
Ce que ça signifie : Environ 14.2G ont changé entre les snapshots. C’est votre charge de réplication pour cet intervalle.
Décision : Comparez à la bande passante disponible et à votre fenêtre de réplication. Si vous ne pouvez pas transférer le delta dans le temps imparti, vous n’atteindrez pas le RPO sous charge.
Tâche 7 : Effectuer une réplication complète initiale dans un namespace sûr
cr0x@prod1:~$ zfs send -w tank/prod/app@dr-2025-12-26_1100 | ssh dr1 "zfs receive -u -o mountpoint=none -d drpool/recv"
receiving full stream of tank/prod/app@dr-2025-12-26_1100 into drpool/recv/tank/prod/app@dr-2025-12-26_1100
Ce que ça signifie : -w envoie un flux chiffré brut (les clés restent sur l’expéditeur ; les propriétés de chiffrement sont préservées). -u empêche le montage automatique à la réception. -o mountpoint=none évite les collisions de montage accidentelles.
Décision : Si vous avez besoin que l’hôte DR monte et serve les données, planifiez le chargement des clés et les ajustements de mountpoint. Si c’est juste une réplique, laissez-la démontée par défaut.
Tâche 8 : Réplication incrémentielle (le travail quotidien réel)
cr0x@prod1:~$ zfs send -w -I tank/prod/app@dr-2025-12-26_1100 tank/prod/app@dr-2025-12-26_1115 | ssh dr1 "zfs receive -u -dF drpool/recv"
receiving incremental stream of tank/prod/app@dr-2025-12-26_1115 into drpool/recv/tank/prod/app@dr-2025-12-26_1115
Ce que ça signifie : -I envoie tous les snapshots intermédiaires. -F force le rollback du dataset cible vers le snapshot le plus récent pour accepter le flux.
Décision : N’utilisez -F que lorsque vous êtes certain que le dataset récepteur est une réplique et que vous acceptez de perdre toute modification locale. Dans les exercices, documentez quand vous l’avez utilisé.
Tâche 9 : Confirmer l’état côté receive et que les datasets ne sont pas montés
cr0x@dr1:~$ zfs get -r -o name,property,value mounted,mountpoint drpool/recv/tank/prod/app | head
NAME PROPERTY VALUE SOURCE
drpool/recv/tank/prod/app mounted no -
drpool/recv/tank/prod/app mountpoint none local
drpool/recv/tank/prod/app/db mounted no -
drpool/recv/tank/prod/app/db mountpoint /var/lib/postgresql received
Ce que ça signifie : Le dataset parent est démonté avec mountpoint none, mais un enfant a un mountpoint reçu défini. C’est une situation classique de « surprise de montage ultérieur ».
Décision : Normalisez les mountpoints côté réception. Pour un namespace de réplique, je préfère forcer mountpoint none sur tout l’arbre, puis définir des mountpoints explicites uniquement sur l’instance restaurée.
Tâche 10 : Remplacer en toute sécurité les mountpoints hérités/reçus
cr0x@dr1:~$ zfs set -r mountpoint=none drpool/recv/tank/prod/app
cr0x@dr1:~$ zfs get -r -o name,property,value mountpoint drpool/recv/tank/prod/app | head -n 6
NAME PROPERTY VALUE SOURCE
drpool/recv/tank/prod/app mountpoint none local
drpool/recv/tank/prod/app/db mountpoint none local
drpool/recv/tank/prod/app/logs mountpoint none local
Ce que ça signifie : Vous avez neutralisé les mountpoints sur l’ensemble de l’arbre de réplique.
Décision : Gardez les répliques inertes. Créez une instance « restaurée » séparée (clone ou promotion) avec des mountpoints réels pour démarrer les services.
Tâche 11 : Créer une copie restaurée écrivable sans perturber la réplique
cr0x@dr1:~$ zfs clone drpool/recv/tank/prod/app@dr-2025-12-26_1115 drpool/restore/prod/app
cr0x@dr1:~$ zfs set mountpoint=/srv/app drpool/restore/prod/app
cr0x@dr1:~$ zfs mount drpool/restore/prod/app
cr0x@dr1:~$ zfs list -o name,mountpoint,origin drpool/restore/prod/app
NAME MOUNTPOINT ORIGIN
drpool/restore/prod/app /srv/app drpool/recv/tank/prod/app@dr-2025-12-26_1115
Ce que ça signifie : Vous avez maintenant un clone écrivable pour l’exercice tout en gardant la réplique intacte.
Décision : Restaurez toujours dans un nouveau dataset quand c’est possible. C’est une soupape de sécurité contre l’erreur humaine et pour répéter les exercices.
Tâche 12 : Charger les clés de chiffrement côté DR (si nécessaire)
cr0x@dr1:~$ zfs get -o name,property,value keystatus,encryptionroot drpool/restore/prod/app
NAME PROPERTY VALUE
drpool/restore/prod/app keystatus unavailable
drpool/restore/prod/app encryptionroot drpool/recv/tank/prod/app
cr0x@dr1:~$ zfs load-key -L file:///etc/zfs/keys/prod_app.key drpool/restore/prod/app
cr0x@dr1:~$ zfs get -o name,property,value keystatus drpool/restore/prod/app
NAME PROPERTY VALUE
drpool/restore/prod/app keystatus available
Ce que ça signifie : Les clés étaient indisponibles jusqu’à leur chargement. Sans cela, les montages et le démarrage des services échoueront.
Décision : Dans votre runbook, rendez le chargement des clés explicite, avec qui y a accès et où les clés se trouvent. Si la réponse est « dans le répertoire perso de quelqu’un », corrigez-le avant le prochain exercice.
Tâche 13 : Mesurer le débit réel d’un pipeline send/receive
cr0x@prod1:~$ zfs send -w tank/prod/app@dr-2025-12-26_1115 | pv -brt | ssh dr1 "zfs receive -u -d drpool/recv"
2.10GiB 0:00:18 [ 119MiB/s] [ <=> ]
Ce que ça signifie : Le débit de bout en bout est d’environ 119MiB/s. Cela inclut CPU, réseau et disque aux deux bouts.
Décision : Comparez à vos tailles de delta et à la fenêtre RPO. Si vous avez besoin de 14G toutes les 15 minutes, 119MiB/s est acceptable ; si vous avez besoin de 200G, vous rêvez.
Tâche 14 : Identifier si le goulot est I/O disque, CPU ou réseau
cr0x@dr1:~$ iostat -xz 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
18.42 0.00 6.11 21.37 0.00 54.10
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 12.0 10240.0 0.0 0.00 1.20 853.3 410.0 92800.0 2.0 0.49 9.80 226.3 4.10 92.0
Ce que ça signifie : Un %util élevé et une charge d’écriture suggèrent que le disque du récepteur est proche de la saturation. L’iowait est significatif.
Décision : Si le disque est saturé, l’optimisation du réseau n’aidera pas. Envisagez des vdevs plus rapides, l’alignement du recordsize, ou un staging vers un pool plus rapide.
Tâche 15 : Confirmer la lignée des snapshots (pourquoi les incrémentiels échouent)
cr0x@prod1:~$ zfs get -o name,property,value guid tank/prod/app@dr-2025-12-26_1100
NAME PROPERTY VALUE
tank/prod/app@dr-2025-12-26_1100 guid 1638672096235874021
cr0x@dr1:~$ zfs get -o name,property,value guid drpool/recv/tank/prod/app@dr-2025-12-26_1100
NAME PROPERTY VALUE
drpool/recv/tank/prod/app@dr-2025-12-26_1100 guid 1638672096235874021
Ce que ça signifie : Le GUID correspond ; le récepteur possède l’instance exacte du snapshot nécessaire pour les incrémentiels.
Décision : Si les GUID diffèrent, votre incrémentiel ne s’appliquera pas. Vous aurez besoin d’un nouveau send complet ou d’une chaîne de réplication corrigée.
Tâche 16 : Valider les propriétés de dataset qui peuvent casser les restaurations (ACLs, xattrs, sensibilité à la casse)
cr0x@prod1:~$ zfs get -o name,property,value acltype,xattr,casesensitivity -r tank/prod/app
NAME PROPERTY VALUE
tank/prod/app acltype posixacl
tank/prod/app xattr sa
tank/prod/app casesensitivity sensitive
tank/prod/app/db acltype posixacl
tank/prod/app/db xattr sa
tank/prod/app/db casesensitivity sensitive
Ce que ça signifie : Des propriétés qui impactent la sémantique applicative sont définies.
Décision : Assurez-vous que la réception les préserve (réplication des propriétés) ou que vous les définissez explicitement sur le dataset de restauration. Un stockage xattr mismatched peut devenir une surprise de performance.
Mode opératoire de diagnostic rapide : quoi vérifier en premier/deuxième/troisième
Pendant un exercice (ou une vraie panne), le pipeline de réplication devient lent et les gens commencent immédiatement à modifier des choses.
Ne le faites pas. Diagnostiquez dans un ordre strict pour ne pas « réparer » la mauvaise couche et ajouter des variables.
Premier : est-ce bloqué sur le pool récepteur ?
- Vérifier :
zpool statuspour un resilver/scrub en cours ;iostat -xzpour un %util proche de 100% et des await élevés. - Interprétation : Si le récepteur est occupé (resilver, scrub, douleur SMR, vdevs saturés), le débit de receive s’effondre indépendamment de la vitesse de l’expéditeur.
- Action : Suspendez l’exercice, replanifiez autour du scrub/resilver, ou recevez temporairement dans un pool de staging plus rapide.
Deuxième : est-ce le réseau ou la surcharge SSH ?
- Vérifier : débit observé avec
pv; CPU sur expéditeur/récepteur ; erreurs et drops NIC avec les outils OS. - Interprétation : Si le CPU est saturé sur un seul cœur pendant le chiffrement SSH, vous avez trouvé votre plafond.
- Action : Utilisez des chiffrements plus rapides, activez l’offload matériel si disponible, ou répliquez sur un réseau de confiance avec un transport alternatif (selon la politique). N’« optimisez » pas la sécurité en panique.
Troisième : est-ce un comportement au niveau ZFS (recordsize, compression, sync, vdevs spéciaux) ?
- Vérifier : propriétés des datasets, zvol vs filesystem, et si la charge est des écritures aléatoires petites ou des séquentielles larges.
- Interprétation : Un dataset DB avec
recordsize=16Kse comportera différemment qu’un dataset média avecrecordsize=1M. - Action : Alignez le recordsize et envisagez de séparer les datasets selon la charge. En DR, le chemin de restauration révèle souvent des incompatibilités ignorées en production.
Quatrième : est-ce un problème de chaîne de réplication ?
- Vérifier : snapshots manquants, mismatch de GUID, ou rollbacks forcés qui ont élagué l’historique nécessaire.
- Interprétation : « L’envoi incrémentiel échoue » signifie souvent « l’historique des snapshots n’est pas ce que vous pensez ».
- Action : Arrêtez d’essayer des flags au hasard. Confirmez la lignée, puis décidez : reconstruire à partir d’un send complet ou reconstituer la chaîne attendue.
Erreurs courantes : symptômes → cause racine → correction
1) Symptôme : le receive incrémentiel échoue avec « does not exist » ou « incremental source … is not found »
Cause racine : le récepteur n’a pas le snapshot de base exact (mauvais nom, élagué, ou lignée GUID différente après une restauration/rollback).
Correction : listez les snapshots des deux côtés ; comparez les GUIDs ; effectuez un nouveau full send pour rétablir une chaîne propre. Évitez les suppressions manuelles de snapshots sur l’arbre de réplique du récepteur.
2) Symptôme : la réception « réussit » mais les datasets se montent dans les chemins de production sur l’hôte DR
Cause racine : les propriétés mountpoint reçues ont été appliquées, et zfs mount -a (ou le démarrage) les a montées.
Correction : recevoir avec -u ; forcer mountpoint=none sur l’arbre de réplique ; ne définir des mountpoints que sur les clones de restauration.
3) Symptôme : l’exercice de restauration bloque à « chargement des clés » et personne ne les trouve
Cause racine : la gestion des clés de chiffrement a été traitée comme « le problème de quelqu’un », pas comme une dépendance opérationnelle.
Correction : définissez la garde des clés, l’emplacement de stockage, et la procédure d’accès ; testez le chargement des clés à chaque exercice ; documentez l’accès d’urgence avec approbations.
4) Symptôme : le débit de réplication est correct la nuit mais catastrophique en heures ouvrées
Cause racine : liens réseau partagés, politique QoS, charges concurrentes sur expéditeur/récepteur, ou scrubs programmés pendant les heures de pointe.
Correction : mesurez pendant le pic ; programmez les scrubs en dehors des fenêtres de réplication ; mettez en place du shaping si besoin ; envisagez des cibles de staging ou des liens dédiés.
5) Symptôme : « cannot receive: failed to read from stream » en cours de transfert
Cause racine : session SSH rompue, mismatch MTU, pertes réseau, ou manque d’espace provoquant des aborts qui remontent comme erreurs de flux.
Correction : vérifiez l’espace libre du récepteur ; vérifiez les logs pour déconnexion ; relancez avec supervision ; préférez les flux reprenables si votre version ZFS les supporte, et gardez suffisamment de marge.
6) Symptôme : l’application démarre, mais les données sont subtilement incorrectes ou anciennes
Cause racine : vous avez restauré le mauvais snapshot (ambiguïté de nommage), ou l’appli nécessite un état supplémentaire (WAL, stockage d’objets, secrets) non couvert par la réplication des datasets.
Correction : imposez des règles de nomination et de sélection des snapshots ; ajoutez les dépendances non-ZFS au périmètre DR ; validez par une vraie transaction métier pendant l’exercice.
7) Symptôme : le receive est lent et le CPU est saturé, mais les disques sont inactifs
Cause racine : overhead du cipher SSH, coût de compression/décompression, ou goulot mono-thread dans le pipeline.
Correction : profilez le CPU ; ajustez la sélection de chiffrements ; envisagez la réplication sur un réseau isolé de confiance avec un transport approprié ; évitez d’empiler des compressions sur plusieurs couches sans réfléchir.
8) Symptôme : la restauration fonctionne une fois, puis les exercices suivants deviennent plus salissants et lents
Cause racine : l’hôte DR devient un tiroir à bazar de datasets à moitié restaurés, montages et répliques modifiées ; « juste une correction rapide » devient de l’état persistant.
Correction : traitez l’environnement DR comme du code : reconstruisez ou réinitialisez entre les exercices ; gardez les répliques en lecture seule ; restaurez via clone et détruisez après l’exercice.
Trois micro-récits d’entreprise tirés du réel
Micro-récit 1 : L’incident causé par une mauvaise hypothèse
Une entreprise de taille moyenne disposait de deux sites et d’un dispositif de réplication ZFS propre. La production envoyait des snapshots horaires vers un hôte DR.
L’équipe était confiante car les logs de receive montraient « success » depuis des mois.
Puis un problème de contrôleur de stockage a détruit le pool primaire. Pas catastrophique—exactement pour quoi sert le DR.
Ils ont promu le dataset DR et tenté de remonter les services. Le système de fichiers s’est monté. L’application a démarré. La base de données a refusé.
La mauvaise hypothèse : « Nous répliquons le dataset de l’app, donc nous répliquons tout le système. » En réalité, les logs de la base de données étaient sur un dataset séparé ajouté plus tard.
Il n’était pas inclus dans le job de réplication. Personne ne l’a remarqué parce que rien n’a échoué pendant la réplication ; cela s’est simplement manifesté par une dépendance manquante.
Sous la pression de la panne, quelqu’un a essayé de « réparer » en copiant le dataset manquant depuis une sauvegarde VM obsolète. La base a redémarré, mais avec un décalage temporel.
Ils se sont retrouvés avec un service en ligne mais logiquement incohérent—pire que l’indisponibilité parce que l’intégrité des données était en question.
L’amélioration post-incident n’était pas exotique : un inventaire des datasets par service, des vérifications de couverture de réplication, et un exercice DR exigeant un vrai chemin d’écriture de bout en bout.
La leçon n’était pas « ZFS a échoué ». La leçon était « notre modèle mental a échoué, et ZFS ne nous en a pas empêchés ».
Micro-récit 2 : L’optimisation qui s’est retournée contre eux
Une autre organisation voulait une réplication plus rapide. Quelqu’un a remarqué l’utilisation CPU pendant la réplication SSH et a décidé d’optimiser.
Ils ont modifié le pipeline, ajouté une compression supplémentaire, et affiné quelques flags. Cela paraissait bien lors d’un test rapide : flux plus petits, débit de pointe supérieur.
Un mois plus tard, les receives DR ont commencé à prendre du retard aux heures de pointe. Pas de quelques minutes—de plusieurs heures. La file de réplication a grossi.
L’équipe a d’abord cherché le réseau, puis les disques, puis le scheduler.
Le retour de manivelle : la couche de compression supplémentaire a rendu l’expéditeur lié au CPU sous charge réelle, et cela a augmenté la variance de latence.
Les tests avaient été réalisés sur un système inactif avec ARC chaud, pas sous la réalité désordonnée des écritures de production.
La réplication est devenue fragile : parfois rapide, parfois glaciaire, toujours imprévisible.
La correction fut presque embarrassante : enlever la couche de compression supplémentaire, se fier aux caractéristiques de compression natives de ZFS, et mesurer avec une charge représentative.
Ils ont aussi limité la concurrence et programmé la réplication pour éviter de chevaucher les fenêtres de scrub.
La meilleure optimisation est celle que vous pouvez expliquer à l’astreinte suivante en deux phrases. Si elle nécessite un tableau blanc et une prière, ce n’est pas une optimisation ; c’est un trait de personnalité.
Micro-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une équipe de services financiers avait la réputation d’être douloureusement méthodique. Ils réalisaient des exercices DR trimestriels avec checklist, horodatages, et l’habitude de détruire et reconstruire les datasets de restauration à chaque fois.
Ce n’était pas glamour, donc souvent moqué par des équipes préférant « l’innovation ».
Un incident réel survint pendant une fenêtre de maintenance : un ingénieur a tapé une commande destroy de dataset sur le mauvais hôte.
C’est le genre d’erreur qui arrive quand l’environnement se ressemble et que vos onglets de terminal dépassent votre capacité d’attention.
L’équipe DR n’a pas improvisé. Ils ont suivi le runbook : identifier le dernier bon snapshot sur le récepteur, cloner dans le namespace de restauration, charger les clés, monter, démarrer les services, exécuter les tests smoke.
Parce qu’ils avaient répété les mêmes commandes, personne n’a discuté du snapshot à utiliser ou de l’endroit où placer les mountpoints.
La récupération n’a pas été instantanée, mais elle a été contrôlée. Plus important encore, ils n’ont pas contaminé la réplique en faisant des changements ad hoc pour « faire fonctionner » le système.
La réplique est restée la source de vérité, et le clone restauré était jetable.
Plus tard, les dirigeants ont parlé de « bonne chance ». Ce n’en était pas. C’était une habitude ennuyeuse qui a empêché les humains d’empirer la situation.
Checklists / plan étape par étape
Checklist de conception de l’exercice (avant le jour)
- Choisissez un service et listez chaque dataset dont il dépend (données, DB, logs, configs, secrets si applicable).
- Définissez les cibles RPO et RTO en minutes/heures, pas à la louche.
- Décidez du namespace cible de restauration (
drpool/recvpour répliques,drpool/restorepour restaurations écrites). - Décidez de la méthode de gestion des clés pour les datasets chiffrés ; vérifiez les chemins d’accès pour l’astreinte.
- Définissez la convention de nommage des snapshots utilisée pour le DR (ex.
dr-YYYY-MM-DD_HHMM). - Accordez-vous sur ce qui constitue « service restauré » : tests smoke, transaction synthétique, ou points de santé spécifiques.
- Planifiez l’exercice pendant une fenêtre de charge réaliste au moins une fois par an (les pics dévoilent les mensonges).
Checklist de préparation à la réplication (jour J, pré-vol)
- Sender et receiver pools sains (
zpool status -x). - Le récepteur dispose d’assez d’espace libre pour les snapshots + marge.
- Les datasets répliques sont démontés par défaut (
-u, politiquemountpoint=none). - Confirmer la présence et la fraîcheur des snapshots des deux côtés.
- Confirmer votre politique de rollback (acceptabilité de
zfs receive -Fpour cette réplique).
Plan d’exécution de la restauration (l’exercice lui‑même)
- Déclarer l’heure de début de l’exercice. Notez-la. Le DR sans horodatage n’est que du cosplay.
- Sélectionner le snapshot. Utilisez le snapshot le plus récent réellement présent sur le DR qui satisfait votre RPO.
- Créer un clone de restauration. Ne restaurez jamais en modifiant directement l’arbre de réplique à moins d’aimer vivre dangereusement.
- Définir explicitement les mountpoints. Évitez les mountpoints hérités reçus ; ils sont optimisés pour les surprises.
- Charger les clés (si chiffré). Validez
keystatus=available. - Monter les datasets dans le bon ordre. DB avant app si votre service l’exige.
- Démarrer les services. Utilisez les commandes du gestionnaire de services standard et capturez les logs.
- Exécuter les tests smoke. Une écriture réelle, un chemin de lecture, une requête, ou une connexion utilisateur.
- Enregistrer le RTO. Arrêtez le chronomètre quand le service satisfait les critères, pas quand un dataset est monté.
- Nettoyer. Détruisez les clones de restauration et les mountpoints temporaires ; gardez la réplique intacte.
- Notez ce qui vous a surpris. C’est tout l’intérêt.
Blague n°2 : Un exercice DR est la seule réunion où « nous devrions tout détruire et recommencer » est à la fois correct et encouragé.
FAQ
1) La réplication ZFS est‑elle une sauvegarde ?
Elle peut faire partie d’une stratégie de sauvegarde, mais seule elle est souvent le reflet de vos erreurs. Si un ransomware chiffre des fichiers et que vous répliquez ces changements rapidement,
félicitations : vous avez deux copies du problème. Vous voulez toujours de la rétention, des contrôles d’immuabilité, et idéalement au moins une copie hors ligne ou isolée logiquement.
2) Dois‑je recevoir directement dans les points de montage finaux ?
Pour les exercices DR, non. Recevez dans un namespace inerte avec -u et des mountpoints neutres, puis clonez dans un namespace de restauration avec des mountpoints explicites.
Cela réduit le risque de monter par‑dessus quelque chose d’important ou de démarrer des services contre le mauvais dataset.
3) Quand zfs receive -F est‑il approprié ?
Quand le dataset récepteur est une réplique pure et que vous êtes à l’aise de le remettre en arrière pour accepter les flux entrants.
C’est inapproprié lorsque le récepteur a des modifications locales qui vous importent, ou lorsque vous ne comprenez pas pourquoi c’est nécessaire.
4) Comment choisir quel snapshot restaurer ?
Utilisez le snapshot le plus récent qui est effectivement présent sur le récepteur et qui satisfait votre RPO. Ensuite, validez l’intégrité applicative.
Le nommage des snapshots devrait encoder la finalité (DR vs ad‑hoc) afin que « latest » ne signifie pas accidentellement « l’expérience de quelqu’un ».
5) Et les datasets chiffrés—ai‑je besoin des clés sur l’hôte DR ?
Si vous envoyez des flux chiffrés bruts (zfs send -w), le récepteur peut stocker les données chiffrées sans clés, mais il ne peut pas monter pour usage tant que les clés ne sont pas chargées.
Décidez si les clés sont stockées sur le DR (plus rapide) ou récupérées pendant l’incident (plus sûr). Entraînez‑vous pour l’option choisie.
6) Dois‑je répliquer les propriétés avec -p ?
Parfois. La réplication des propriétés peut préserver des comportements importants (compression, recordsize, ACLs), mais elle peut aussi embarquer des mountpoints et des conventions locales que vous ne voulez pas.
Un compromis courant : répliquer la plupart des propriétés, mais imposer la politique de mountpoint à la réception et restaurer via clone.
7) Pourquoi mon receive est lent alors que l’expéditeur est rapide ?
Parce que la performance du receive est généralement limitée par le récepteur : IOPS d’écriture disque, fragmentation, scrubs/resilvers, et CPU pour checksum/décompression.
Mesurez le débit de bout en bout puis regardez d’abord iostat et l’activité du pool récepteur.
8) Dois‑je tester les restaurations si les logs de réplication montrent « success » ?
Oui. Les logs vous disent « un flux a été appliqué ». Ils ne vous disent pas « le service est récupérable », « les clés peuvent être chargées », « les mountpoints sont sûrs », ou « le RTO est atteignable ».
Les exercices DR détectent les lacunes opérationnelles, pas les bugs du système de fichiers.
9) À quelle fréquence devons‑nous faire un exercice DR ?
Trimestriellement si possible, semestriellement si nécessaire, annuellement seulement si votre environnement change très lentement (ce n’est pas le cas).
Faites au moins un exercice par an sous charge réaliste, et des exercices de table quand le personnel clé ou l’architecture changent.
10) L’hôte DR doit‑il être identique au matériel de production ?
Pas toujours, mais vous avez besoin de prévisibilité de performance. Si le DR est sensiblement plus lent, votre RTO s’allongera.
Si le DR utilise des agencements de disques ou des chemins réseau différents, les exercices doivent mesurer la vitesse réelle de restauration, pas une vitesse théorique.
Conclusion : prochaines étapes programmables cette semaine
Si vous ne « testez les sauvegardes » qu’en vérifiant que des snapshots existent, vous testez la paperasserie. ZFS send/receive est puissant, mais ce n’est pas magique.
Le chemin de restauration est l’endroit où la conception du système rencontre la réalité humaine : nommage, accès aux clés, mountpoints, et la pression du temps.
Étapes concrètes :
- Choisir un service et inventorier ses datasets et dépendances non‑ZFS.
- Définir RPO/RTO et écrire ce que « terminé » signifie au niveau applicatif.
- Construire un namespace de réception sûr avec répliques non montées et mountpoints neutres.
- Réaliser un exercice complet de restauration en utilisant des restaurations basées sur des clones et le chargement explicite des clés.
- Enregistrer les durées et les goulots, puis corriger le plus gros—capacité, clés, ou débit.
- Répéter jusqu’à ce que l’exercice devienne ennuyeux. Ennuyeux = fiable.