ZFS : la réplique que vous croyiez avoir — comment auditer la réplication pour de vrai

Cet article vous a aidé ?

La réplication n’a l’air ennuyeuse que lorsqu’elle fonctionne. Lorsqu’elle ne fonctionne pas, elle se transforme en film d’horreur au ralenti :
le PDG demande « Avons‑nous une copie ? » et vous répondez « Oui, » pendant que votre estomac prépare discrètement une faillite.

ZFS rend dangereusement facile de croire que vous êtes en sécurité parce que quelques snapshots existent quelque part.
Cet article traite de la preuve que la réplique est réelle : actuelle, cohérente, déchiffrable, restaurable et utilisable
dans l’échec exact que vous allez réellement subir.

Ce que signifie une « vraie réplication » en production

« Nous répliquons ZFS » peut vouloir dire au moins six choses différentes, et cinq d’entre elles signifient « on se sent bien jusqu’à ce que ce ne soit plus le cas. »
Une réplique réelle n’est pas seulement « les données existent sur l’autre hôte. » Elle est :

  • Assez actuelle : votre RPO est respecté par observation, pas par optimisme.
  • Cohérente : elle provient d’une chaîne de snapshots cohérente, pas d’un assemblage bricolé.
  • Complète : tous les ensembles de données importants sont inclus (enfants, propriétés et holds quand pertinents).
  • Déchiffrable : si le chiffrement est impliqué, vous pouvez réellement charger les clés et monter les données le pire jour de l’année.
  • Restaurable : vous pouvez promouvoir, rollbacker, monter et fournir le résultat à une application sans faire d’archéologie.
  • Sûre opérationnellement : la réplication ne sabote pas la production via des pics de charge, des snapshots gigantesques ou de la pression arrière.

La réplication ZFS est basée sur les snapshots. C’est à la fois sa superpuissance et son piège. Superpuissance : c’est précis et efficace.
Piège : si un maillon de la chaîne manque, l’« incremental » que vous pensiez transmettre ne l’est plus.
Aussi, le flux envoyé est fidèle au snapshot depuis lequel il a été produit ; il ne se soucie pas que votre base de données ait besoin d’être quiescée et que vous ne l’ayez pas fait.

Voici la règle directrice : auditez le chemin de restauration, pas le chemin d’envoi. Envoyer des données est facile.
Les restaurer sous pression est l’endroit où vos hypothèses non examinées viennent mourir.

Une vérité sèche du monde opérationnel : « Nous avons des sauvegardes » n’est pas un état ; c’est une affirmation qui exige des preuves.
Si vous ne pouvez pas répondre « Quel est le snapshot récupérable le plus récent pour l’ensemble de données X, et combien de temps faudrait‑il pour le remettre en service ? »,
vous n’avez pas de réplication, vous avez des impressions.

Idée paraphrasée de John Allspaw (opérations/fiabilité) : la fiabilité vient de l’apprentissage dans le monde réel et désordonné, pas de croire le plan.
Auditer la réplication est cette boucle d’apprentissage appliquée au stockage.

Faits intéressants et contexte historique

  1. ZFS a été conçu autour de sommes de contrôle de bout en bout (données et métadonnées), rendant la corruption silencieuse détectable—si vous scrubez et surveillez.
  2. Les snapshots sont bon marché dans ZFS parce qu’ils sont des références copy‑on‑write, pas des copies complètes. Ils peuvent néanmoins devenir coûteux si vous les conservez éternellement.
  3. Le ZFS original est sorti de Sun Microsystems ; son approche de réplication (send/receive) a été conçue pour déplacer des deltas de snapshots de manière sûre et déterministe.
  4. OpenZFS est devenu un effort multiplateforme après le déclin de Sun, et la parité des fonctionnalités varie selon la distribution et la version de l’OS—important pour les jetons de reprise et le comportement du chiffrement.
  5. Les flux de réplication peuvent inclure les propriétés des datasets selon les flags ; l’absence de propriétés est un classique échec « ça a restauré mais c’est incorrect ».
  6. Les jetons de reprise existent parce que les envois longs échouent sur les réseaux réels. Ce ne sont pas des décorations ; ce sont ce qui vous empêche de renvoyer 40 To après une coupure de 3 secondes sur le lien.
  7. Le chiffrement ZFS est par dataset, pas par pool, et la gestion des clés sur le récepteur est tout un problème opérationnel séparé.
  8. Les scrubs ne sont pas des sauvegardes, mais ils sont un outil d’audit : ils vous disent si la réplique peut lire ses propres données de manière fiable.

Un modèle d’audit qui attrape les mensonges habituels

Mensonge n°1 : « La réplique existe » (mais ce ne sont pas les bons datasets)

Vous avez répliqué tank/data mais pas tank/data/mysql parce que quelqu’un l’a créé plus tard
et votre script a énuméré les datasets une fois, en 2022, et jamais après. Le récepteur paraît sain. La restauration affiche un regard vide.
Votre audit doit comparer « ce qui doit être protégé » vs « ce qui est protégé » et signaler la dérive.

Mensonge n°2 : « C’est à jour » (mais le planning des snapshots est cassé)

La réplication ne peut pas être plus à jour que le snapshot le plus récent sur l’émetteur. Si les snapshots s’arrêtent, la réplication « réussit » tout en ne déplaçant rien.
Votre audit doit vérifier la création des snapshots, le nommage des snapshots et que le snapshot le plus récent arrive bien sur le récepteur.

Mensonge n°3 : « C’est cohérent » (mais la chaîne est fracturée)

La réplication incrémentale suppose que les deux côtés partagent un snapshot commun. Supprimez‑en un sur le récepteur et votre prochain send incrémental échoue.
Ou pire : cela semble réussir parce que vous êtes repassé à un envoi complet sans le remarquer, provoquant un pic de bande passante et de temps d’exécution.
Auditer signifie vérifier le snapshot de base commun et suivre les envois complets inattendus.

Mensonge n°4 : « C’est restaurable » (mais le récepteur n’est pas utilisable en cas de DR)

Le récepteur peut être en lecture seule, peut avoir canmount=off, peut nécessiter des clés de chiffrement, peut exiger la promotion de clones,
peut manquer de points de montage attendus, ou peut restaurer avec des propriétés recordsize/compression incorrectes et dégrader fortement les performances.
Un véritable audit inclut un test de restauration non destructif sur un hôte de staging, ainsi qu’un runbook documenté « promote and mount ».

Mensonge n°5 : « Nous avons la bande passante » (mais vous n’avez pas le temps)

Votre réplication peut « se terminer éventuellement » mais quand même manquer le RPO et le RTO parce que le delta a grandi plus vite que le lien ne peut le transférer.
Auditer signifie mesurer les tailles d’envoi, les débits de réception et la croissance des snapshots au fil du temps. Pas de supposition. Pas de « ça devrait aller ».

Blague n°1 : Les plans de réplication sont comme les parapluies—tout le monde s’en souvient juste après qu’il commence à pleuvoir.

Playbook de diagnostic rapide

C’est la séquence « il est 02:13 et la réplication est en retard ». L’objectif est de trouver le goulot d’étranglement en quelques minutes, pas en heures.
Vérifiez ceci dans l’ordre ; arrêtez‑vous quand vous trouvez la première contrainte ferme.

Premier : Y a‑t‑il quelque chose à répliquer ?

  • La création des snapshots s’exécute‑t‑elle sur l’émetteur ?
  • Le snapshot le plus récent sur l’émetteur est‑il plus récent que celui du récepteur ?
  • Êtes‑vous bloqué sur un snapshot commun manquant (chaîne incrémentale cassée) ?

Deuxième : Le processus de réplication déplace‑t‑il réellement des données ?

  • Est‑ce que zfs receive s’exécute et consomme le flux ?
  • Êtes‑vous bloqué sur un jeton de reprise ?
  • Le réseau est‑il saturé ou instable ?

Troisième : Le récepteur est‑il capable d’écrire ?

  • État du pool : dégradé, suspendu, ou manque d’espace ?
  • Latence IOPS : les disques étouffent‑ils ou le SLOG est‑il absent/mal utilisé ?
  • Un scrub/resilver intensif concurrence‑t‑il la réplication ?

Quatrième : L’émetteur est‑il le goulot ?

  • Surcharge CPU due à la compression/le chiffrement pendant l’envoi ?
  • Delta de snapshots énorme à cause d’erreurs de rétention ?
  • Disposition des datasets (recordsize, sync) provoquant des IO pathologiques ?

Cinquième : Perdez‑vous du temps à cause de retouches évitables ?

  • Faites‑vous accidentellement des envois complets parce que le snapshot de base ne correspond pas ?
  • N’utilisez‑vous pas les jetons de reprise sur des liens instables ?
  • Renvoyez‑vous des propriétés et provoquez‑vous du churn inutile ?

Tâches d’audit pratiques (commandes, sorties, décisions)

Ce ne sont pas des « choses à connaître ». Ce sont les commandes que vous exécutez quand vous voulez cesser de croire et commencer à savoir.
Je vais supposer un hôte émetteur zfs-prod-01 avec pool tank, et un récepteur zfs-dr-01 avec pool backup.

Tâche 1 : Confirmer l’état des pools des deux côtés

cr0x@server:~$ zpool status -x
all pools are healthy

Ce que cela signifie : aucun défaut connu, pas de vdev dégradé, pas d’IO suspendu.
Si vous voyez autre chose, la correction de la réplication est secondaire à la survie du pool.
Décision : Si ce n’est pas sain, mettez la réplication agressive en pause et réparez d’abord le pool ; un récepteur dégradé peut augmenter silencieusement le RTO.

Tâche 2 : Vérifier que le récepteur a suffisamment d’espace libre pour les deltas pires cas

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint backup
NAME    USED  AVAIL  REFER  MOUNTPOINT
backup  62.1T 8.40T   128K  /backup

Ce que cela signifie : seulement 8.4T libres. Si votre prochain delta fait 10T à cause d’une erreur de rétention, le receive échouera en cours de flux.
Décision : Définissez une politique stricte de « minimum d’espace libre » (et alertez dessus). Si en dessous du seuil, prunez les snapshots ou augmentez la capacité avant le prochain gros envoi.

Tâche 3 : Énumérer ce que vous croyez répliquer (émetteur)

cr0x@server:~$ zfs list -r -o name,type,mountpoint tank/data
NAME                 TYPE  MOUNTPOINT
tank/data            filesystem  /tank/data
tank/data/mysql      filesystem  /tank/data/mysql
tank/data/pg         filesystem  /tank/data/pg
tank/data/home       filesystem  /tank/data/home

Ce que cela signifie : ceci est votre périmètre souhaité. Vos outils de réplication doivent couvrir tout cela (ou exclure explicitement des parties).
Décision : Si vos scripts répliquent seulement une liste fixe, remplacez‑les par une découverte récursive des datasets plus des règles allow/deny versionnées.

Tâche 4 : Énumérer ce qui existe réellement sur le récepteur

cr0x@server:~$ zfs list -r -o name,type,mountpoint backup/data
NAME                 TYPE  MOUNTPOINT
backup/data          filesystem  /backup/data
backup/data/mysql    filesystem  none
backup/data/home     filesystem  none

Ce que cela signifie : backup/data/pg est manquant. De plus, les points de montage sont none (ce qui peut être intentionnel pour le DR).
Décision : Les datasets manquants sont un problème bloquant. Corrigez la portée de la réplication avant de discuter performance.

Tâche 5 : Vérifier les horodatages des snapshots les plus récents sur émetteur et récepteur (réalité RPO)

cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation -r tank/data/mysql | tail -n 3
tank/data/mysql@rep_2026-02-04_0000  Tue Feb  4 00:00 2026
tank/data/mysql@rep_2026-02-04_0030  Tue Feb  4 00:30 2026
tank/data/mysql@rep_2026-02-04_0100  Tue Feb  4 01:00 2026
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation -r backup/data/mysql | tail -n 3
backup/data/mysql@rep_2026-02-04_0000  Tue Feb  4 00:00 2026
backup/data/mysql@rep_2026-02-04_0030  Tue Feb  4 00:30 2026
backup/data/mysql@rep_2026-02-04_0100  Tue Feb  4 01:00 2026

Ce que cela signifie : le récepteur correspond à l’émetteur jusqu’à 01:00. Le RPO pour ce dataset est actuellement « minutes », pas « peut‑être ».
Décision : Automatiser le suivi. Si le snapshot le plus récent du récepteur accuse un retard supérieur à la politique, alertez l’on‑call. C’est l’essentiel.

Tâche 6 : Confirmer que le snapshot de base incrémental existe des deux côtés

cr0x@server:~$ zfs list -t snapshot -o name -r tank/data/mysql | grep rep_2026-02-03_2300
tank/data/mysql@rep_2026-02-03_2300
cr0x@server:~$ zfs list -t snapshot -o name -r backup/data/mysql | grep rep_2026-02-03_2300
backup/data/mysql@rep_2026-02-03_2300

Ce que cela signifie : la base commune existe. Si elle n’existe pas, le prochain envoi -i échouera avec « incremental source does not exist. »
Décision : Si la base manque, choisissez entre (a) restaurer le snapshot manquant (s’il est disponible), (b) faire un envoi complet, ou (c) reconstruire le dataset du récepteur.

Tâche 7 : Détecter les envois complets inattendus en estimant la taille des deltas

cr0x@server:~$ zfs send -nPv -i tank/data/mysql@rep_2026-02-04_0000 tank/data/mysql@rep_2026-02-04_0100
size	2.31G
incremental	tank/data/mysql@rep_2026-02-04_0000	tank/data/mysql@rep_2026-02-04_0100
no-op bytes	132K

Ce que cela signifie : le delta attendu est d’environ 2.31G. Si vous exécutez ceci et voyez « size 4.8T », vous allez trouver la religion.
Décision : Si la taille du delta est bien au‑dessus de la normale, arrêtez‑vous et investiguez la rétention des snapshots, des fichiers en fuite, ou une chaîne incrémentale brisée avant de saturer les liens pendant des jours.

Tâche 8 : Vérifier les jetons de reprise sur le récepteur (réplication bloquée)

cr0x@server:~$ zfs get -H -o name,value receive_resume_token backup/data/mysql
backup/data/mysql	1-EMyVd...AAAB

Ce que cela signifie : un jeton existe : un receive a été interrompu. Votre automatisation peut démarrer aveuglément de nouveaux envois qui ne peuvent pas s’attacher.
Décision : Soit reprendre le flux en utilisant le jeton, soit annuler explicitement et nettoyer l’état (avec précaution). Traitez les jetons comme un journal de transaction, pas comme du désordre.

Tâche 9 : Reprendre un envoi interrompu en toute sécurité

cr0x@server:~$ TOKEN=$(zfs get -H -o value receive_resume_token backup/data/mysql)
cr0x@server:~$ ssh zfs-prod-01 "zfs send -t $TOKEN" | zfs receive -s -F backup/data/mysql
cr0x@server:~$ echo $?
0

Ce que cela signifie : code de sortie 0 : la reprise du receive est terminée.
Décision : Ajoutez une logique consciente des jetons à vos outils de réplication. Si votre processus ne supporte pas cela, vous êtes à un lien instable d’envoyer des téraoctets en double.

Tâche 10 : Valider la réplication des propriétés (le contrôle « ça a restauré mais c’est faux »)

cr0x@server:~$ zfs get -H -o name,property,value compression,recordsize,atime,canmount tank/data/mysql
tank/data/mysql	compression	zstd
tank/data/mysql	recordsize	16K
tank/data/mysql	atime	off
tank/data/mysql	canmount	on
cr0x@server:~$ zfs get -H -o name,property,value compression,recordsize,atime,canmount backup/data/mysql
backup/data/mysql	compression	zstd
backup/data/mysql	recordsize	128K
backup/data/mysql	atime	on
backup/data/mysql	canmount	noauto

Ce que cela signifie : le récepteur diffère : recordsize et atime ne correspondent pas, et canmount est délibérément différent.
Un décalage de recordsize peut anéantir les performances d’une base de données après un basculement.
Décision : Décidez quelles propriétés doivent correspondre pour le DR. Répliquez‑les intentionnellement (ou appliquez‑les via une politique post‑receive).
N’« optimisez » pas accidentellement la réplique au point de la rendre inutilisable.

Tâche 11 : Confirmer l’état du chiffrement et la disponibilité des clés (ne le découvrez pas pendant le DR)

cr0x@server:~$ zfs get -H -o name,property,value encryption,keystatus,keylocation tank/secure/hr
tank/secure/hr	encryption	aes-256-gcm
tank/secure/hr	keystatus	available
tank/secure/hr	keylocation	prompt
cr0x@server:~$ zfs get -H -o name,property,value encryption,keystatus,keylocation backup/secure/hr
backup/secure/hr	encryption	aes-256-gcm
backup/secure/hr	keystatus	unavailable
backup/secure/hr	keylocation	prompt

Ce que cela signifie : le récepteur contient des données chiffrées mais aucune clé chargée. Cela peut être correct (sécurité) mais doit être planifié opérationnellement.
Décision : Mettez en place un processus d’entiercement des clés et un runbook de chargement des clés pour le DR. Si personne ne peut charger les clés à 03:00, vous n’avez pas de réplique.

Tâche 12 : Effectuer un test de montage non destructif sur le récepteur (prouver le chemin de restauration)

cr0x@server:~$ zfs clone backup/data/mysql@rep_2026-02-04_0100 backup/test-restore/mysql
cr0x@server:~$ zfs set canmount=noauto mountpoint=/mnt/restore-mysql backup/test-restore/mysql
cr0x@server:~$ zfs mount backup/test-restore/mysql
cr0x@server:~$ zfs list -o name,mountpoint backup/test-restore/mysql
NAME                     MOUNTPOINT
backup/test-restore/mysql /mnt/restore-mysql

Ce que cela signifie : vous pouvez matérialiser une vue à un point dans le temps sans toucher le dataset répliqué principal.
Décision : Faites de cet exercice une opération planifiée. Si le montage nécessite une « connaissance tribale », écrivez‑la et répétez.

Tâche 13 : Vérifier l’intégrité des données avec le statut de scrub sur le récepteur

cr0x@server:~$ zpool status backup
  pool: backup
 state: ONLINE
  scan: scrub repaired 0B in 05:14:02 with 0 errors on Sun Feb  2 03:12:44 2026
config:

	NAME        STATE     READ WRITE CKSUM
	backup       ONLINE       0     0     0
	  raidz2-0   ONLINE       0     0     0
	    sda     ONLINE       0     0     0
	    sdb     ONLINE       0     0     0
	    sdc     ONLINE       0     0     0
	    sdd     ONLINE       0     0     0

Ce que cela signifie : le scrub s’est terminé avec zéro erreur. C’est la preuve que votre réplique peut lire elle‑même ses blocs.
Décision : Si les scrubs montrent des erreurs, considérez le récepteur comme suspect jusqu’à réparation ; répliquer sur un média défaillant n’est pas de la « sécurité ».

Tâche 14 : Rechercher une dérive de rétention des snapshots (émetteur et récepteur doivent s’accorder)

cr0x@server:~$ zfs list -t snapshot -o name -r tank/data/mysql | wc -l
336
cr0x@server:~$ zfs list -t snapshot -o name -r backup/data/mysql | wc -l
92

Ce que cela signifie : le récepteur a beaucoup moins de snapshots. Peut‑être intentionnel. Peut‑être qu’un nettoyage s’exécute uniquement sur le DR et a cassé la chaîne incrémentale.
Décision : Alignez la politique de rétention avec la méthode de réplication. Si vous prunez sur le récepteur, assurez‑vous que les snapshots de base nécessaires aux incrémentaux sont préservés.

Tâche 15 : Vérifier que la réplication ne concurrence pas le resilver/scrub au mauvais moment

cr0x@server:~$ zpool iostat -v backup 5 2
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
backup                      62.1T  8.40T    120    980   9.2M  112M
  raidz2-0                  62.1T  8.40T    120    980   9.2M  112M
    sda                         -      -     30    240   2.3M   28M
    sdb                         -      -     28    260   2.1M   29M
    sdc                         -      -     32    250   2.4M   28M
    sdd                         -      -     30    230   2.4M   27M

Ce que cela signifie : les écritures sont élevées ; si la latence est aussi haute, le receive peut ralentir. Si vous voyez scrubs/resilver en cours, attendez‑vous à une aggravation.
Décision : Planifiez des fenêtres de réplication ou limitez le débit d’envoi quand le pool est déjà occupé par des opérations de réparation.

Tâche 16 : Valider quels snapshots retiennent de l’espace (pourquoi les deltas sont énormes)

cr0x@server:~$ zfs holds -r tank/data/mysql@rep_2026-02-01_0000
NAME                                  TAG     TIMESTAMP
tank/data/mysql@rep_2026-02-01_0000    keep    Sun Feb  1 00:00 2026

Ce que cela signifie : un hold empêche la suppression. Les holds sont utiles, mais ils peuvent aussi bloquer des mois de churn.
Décision : Auditez les holds et rendez‑les intentionnels. Si « keep » est placé par un humain, enregistrez pourquoi et pour combien de temps.

Blague n°2 : Un jeton de reprise est comme ce tiroir de câbles mystères—inutile jusqu’à ce que ce soit soudainement la seule chose qui sauve votre week‑end.

Trois mini‑histoires d’entreprise (comment cela échoue)

1) Incident causé par une fausse hypothèse : « La réplication a réussi parce que le job a dit OK »

Une entreprise de taille moyenne effectuait une réplication ZFS de la production vers un site DR. Le job de réplication était un script shell propre
lancé par cron. Il écrivait des logs. Il envoyait même un e‑mail « succès » si le code de sortie de la chaîne était zéro.
Tout le monde dormait bien. Trop bien.

Le hic : les snapshots étaient créés par un autre job sur l’hôte de production. Ce job a échoué silencieusement après une mise à jour de paquet
qui a changé un chemin de script. La réplication a continué, n’a trouvé aucun nouveau snapshot, et n’a rien fait—proprement.
Les logs affichaient des runs réussis parce que l’étape send a correctement envoyé rien et l’étape receive a correctement reçu rien.

Des mois plus tard, une panne de production a exigé un basculement. Les datasets DR existaient. Ils se sont montés. Les services ont démarré.
Et les données étaient assez anciennes pour voter.
Personne n’avait mesuré « snapshot le plus récent sur le récepteur vs l’émetteur », donc aucune alerte n’a été déclenchée. Le système de réplication était « vert »
de la manière qui devrait vous effrayer.

La correction était ennuyeuse et efficace : ils ont ajouté un contrôle RPO strict qui comparait les horodatages des snapshots par dataset, plus une alerte si
« l’âge du snapshot le plus récemment répliqué » dépassait la politique. Ils ont aussi fait de la création des snapshots une partie de la même unité de travail :
une orchestration, un log, un jeu de métriques.

2) Optimisation qui s’est retournée contre eux : « Réduisons le nombre de snapshots sur le DR pour économiser de l’espace »

Une autre organisation avait un pool DR limité. Quelqu’un a regardé le nombre de snapshots et a décidé que le côté DR n’en avait pas besoin autant.
L’hôte DR exécutait une politique de nettoyage qui supprimait les anciens snapshots plus agressivement que la production.
Sur le papier, c’était efficace : moins de snapshots, moins d’espace, moins d’overhead métadonnées.

Puis les incrémentaux ont commencé à échouer de façon intermittente. L’outil de réplication essayait d’envoyer depuis le dernier snapshot commun,
mais ce snapshot avait été supprimé sur le récepteur. L’outil a réagi en retombant sur un envoi complet—parce que l’auteur du script
pensait « mieux vaut répliquer lentement que d’échouer ». Ça a marché, jusqu’à ce que ça ne marche plus.

Les envois complets ont duré des jours. Ils ont percuté d’autres IO. Ils ont saturé le WAN. Ils ont augmenté l’âge des snapshots, ce qui a accru les deltas,
rendant les envois suivants encore pires. Boucle de rétroaction positive classique. Le système ne s’est pas effondré à cause d’un seul bug. Il s’est effondré à cause d’une
« optimisation » et de trois garde‑fous manquants.

La solution finale : unifier la logique de rétention entre émetteur et récepteur, et protéger explicitement les N derniers snapshots sur le
récepteur avec des holds pour que les incrémentaux aient toujours une base. L’équipe a aussi interdit la retombée automatique vers des envois complets sans
une alerte bruyante et une décision humaine.

3) Pratique ennuyeuse mais correcte qui a sauvé la mise : « Drills de restauration trimestriels sur un staging box »

Une entreprise régulée (pensez : paperasse de conformité qui se reproduit la nuit) avait une habitude que les ingénieurs moquaient d’abord :
chaque trimestre, ils effectuaient un drill de restauration. Pas un exercice de table. Une vraie restauration sur un hôte de staging, avec la même famille d’OS,
mêmes flags de fonctionnalité ZFS, et une version réduite de l’application.

La checklist du drill était simple. Confirmer que le snapshot le plus récent existe. Le cloner. Le monter. Faire une vérification d’intégrité légère.
Démarrer le service pointant vers le dataset restauré. Valider un comportement applicatif basique. Documenter les temps d’exécution.
Puis détruire le clone. Pas d’héroïsme, pas de « on s’en souviendra plus tard ».

Lorsqu’ils ont ensuite subi un incident de ransomware en production, l’équipe stockage n’a pas eu à inventer un plan de récupération en réunion.
Ils avaient déjà une mémoire musculaire pour : « identifier le dernier snapshot known‑good, cloner sur le DR, promouvoir si nécessaire, lancer le service. »
La restauration n’a toujours pas été agréable—rien n’est agréable pendant un ransomware—mais elle était exécutable.

Le plus grand gain a été psychologique : parce qu’ils avaient pratiqué, ils n’ont pas perdu des heures à se disputer pour savoir si la réplique était valide.
Ils débattaient quel snapshot utiliser, pas si les snapshots existaient.
Voilà à quoi ressemble la compétence : sans glamour, répétée et rapide.

Erreurs courantes (symptôme → cause racine → correction)

La réplication « réussit » mais les données DR sont anciennes

  • Symptôme : les jobs indiquent succès ; le snapshot le plus récent sur le récepteur a des heures/jours de retard.
  • Cause racine : la création des snapshots a cessé ; la réplication a fonctionné sans nouveaux snapshots ; aucun contrôle RPO n’existait.
  • Correction : alerter sur « l’âge du dernier snapshot par dataset » et « l’âge du dernier snapshot répliqué ». Traitez « pas de nouveaux snapshots » comme une défaillance sauf si c’est explicitement attendu.

Les envois incrémentaux échouent : « does not exist » ou erreurs « incremental source »

  • Symptôme : erreurs send/receive mentionnant des snapshots manquants ; l’automatisation boucle sur des retries infinis.
  • Cause racine : le récepteur a prune les snapshots ou n’a jamais reçu la base ; mismatch de nommage ; réplication démarrée au milieu de la chaîne.
  • Correction : imposer la symétrie de rétention pour la « fenêtre de base » ; utiliser des holds sur le récepteur pour les snapshots base nécessaires ; reconstruire le dataset par un envoi complet quand la chaîne est irrémédiablement cassée.

La réplication est lente malgré une bande passante suffisante

  • Symptôme : le réseau n’est pas saturé, mais le receive avance au ralenti ; latence du pool élevée.
  • Cause racine : les disques du récepteur sont le goulot ; scrub/resilver concurrent ; datasets à petit recordsize provoquant beaucoup d’IOPS.
  • Correction : planifier ou limiter la réplication pendant les opérations de réparation ; mesurer avec zpool iostat ; envisager d’ajuster les propriétés des datasets en production (avec prudence) plutôt que de « corriger » le DR isolément.

La réplique monte, mais les performances applicatives sont terribles après basculement

  • Symptôme : le service DR démarre mais est lent ; les métriques DB sont catastrophiques.
  • Cause racine : divergence des propriétés (recordsize, compression, atime, logbias) ; la réplication n’a pas inclus les propriétés ou le récepteur impose des valeurs par défaut différentes.
  • Correction : définir un ensemble de propriétés « doit‑correspondre » ; répliquer les propriétés intentionnellement ; valider périodiquement les diffs de propriétés et faire des drills de restauration.

Les datasets chiffrés se répliquent, mais le DR ne peut pas les monter

  • Symptôme : les datasets existent sur le DR ; keystatus=unavailable ; montages échouent en incident.
  • Cause racine : la gestion des clés n’est pas intégrée au DR ; les clés requièrent une saisie manuelle par quelqu’un qui dort ou n’est pas disponible.
  • Correction : établir un entiercement des clés et une procédure break‑glass ; tester le chargement des clés sur le DR trimestriellement ; vérifier la compatibilité des flags de fonctionnalités.

La réplication redémarre aléatoirement depuis le début

  • Symptôme : gros transferts se répètent ; le temps des jobs augmente ; la facture WAN devient intéressante.
  • Cause racine : flux interrompus sans reprise ; jetons de reprise ignorés ; l’automatisation lance des envois complets neufs.
  • Correction : utiliser zfs receive -s et une reprise consciente des jetons ; alerter quand un receive_resume_token existe au‑delà d’un seuil ; éviter la « retombée silencieuse vers le full ».

La réplication paraît correcte, mais la hiérarchie des datasets DR est erronée

  • Symptôme : certains enfants manquent ; points de montage étranges ; quotas/réservations absents.
  • Cause racine : le script de réplication n’utilisait pas le mode récursif ; des datasets créés plus tard n’ont jamais été ajoutés ; propriétés non incluses.
  • Correction : répliquer de façon récursive avec exclusions explicites ; auditer la dérive de la liste des datasets ; faire respecter la hiérarchie attendue via un fichier « état désiré ».

Listes de contrôle / plan étape par étape

Checklist hebdomadaire (15–30 minutes)

  1. État des pools : vérifier zpool status -x sur émetteur et récepteur ; tout état non sain est prioritaire.
  2. Contrôle RPO : comparer les horodatages des snapshots les plus récents des deux côtés pour les datasets critiques (bases de données, home dirs, stores d’objets).
  3. Contrôle de périmètre : vérifier que l’arborescence des datasets correspond à ce que vous pensez protéger ; chercher des nouveaux enfants non couverts.
  4. Contrôle de rétention : comparer le nombre de snapshots et assurer que les snapshots de base nécessaires aux incrémentaux existent sur le récepteur.
  5. Contrôle des jetons de reprise : s’assurer qu’aucun receive_resume_token de longue durée n’existe sans action.
  6. Contrôle de capacité : vérifier l’espace libre du récepteur par rapport à votre delta pire cas et marge de sécurité.

Checklist mensuelle (1–2 heures)

  1. Diff de propriétés : échantillonner les datasets critiques et comparer les propriétés qui affectent le comportement en production (recordsize, compression, atime, sync, logbias, quotas).
  2. Revue des scrubs : confirmer que le scrub du récepteur s’est terminé sans erreurs ; investiguer immédiatement toute erreur de checksum ou de lecture.
  3. Dimensionnement des deltas : exécuter zfs send -nPv pour quelques incrémentaux représentatifs et enregistrer les tailles ; surveiller les sauts en escalier.
  4. Injection de défaillance : interrompre intentionnellement un run de réplication et confirmer que la logique de reprise par jeton fonctionne.

Drill de restauration trimestriel (demi‑journée, mais qui rapporte)

  1. Sélectionner un dataset : choisir un dataset à forte valeur (DB ou partage de fichiers clé) et un dataset « large » (beaucoup de petits fichiers).
  2. Cloner le dernier snapshot sur le DR : le monter dans un chemin contrôlé.
  3. Validation applicative : démarrer un service minimal ou un check d’intégrité qui ressemble à la réalité.
  4. Mesurer le temps : enregistrer la durée de chaque étape ; c’est la preuve de votre RTO.
  5. Détruire les clones : nettoyer ; s’assurer que le drill ne gonfle pas l’usage d’espace pendant des semaines.
  6. Mettre à jour le runbook : si quelqu’un a dû « savoir », cela entre dans la procédure.

Règles strictes (celles qui évitent la revue d’incident à 03:00)

  • Pas d’envois complets silencieux. Si les incrémentaux échouent et que vous choisissez un full, c’est une décision humaine avec alerte.
  • Pas de réplication sans surveillance RPO. « Job succeeded » est une métrique dénuée de sens seule.
  • Pas de chiffrement sans procédures DR pour les clés. « Sécurisé mais irrécupérable » est une forme de perte de données.
  • Pas de prune sur le récepteur qui casse les chaînes. Si vous devez prune, vous devez préserver les snapshots de base requis pour les incrémentaux.

FAQ

1) Quelle est la meilleure métrique unique pour l’état de la réplication ?

L’âge du snapshot récupérable le plus récent sur le récepteur, par dataset critique. Pas « succès du job », pas le débit.
L’âge du snapshot se mappe directement au RPO.

2) « Le snapshot existe sur le DR » suffit‑il ?

Non. Vous devez prouver que vous pouvez l’utiliser : le cloner, le monter, charger les clés s’il est chiffré, et valider les données au niveau applicatif.

3) Le dataset DR doit‑il être monté automatiquement ?

Habituellement non. La pratique courante est canmount=noauto ou mountpoint=none sur le DR pour éviter l’utilisation accidentelle.
Mais vous devez documenter exactement comment monter en DR et le tester.

4) Puis‑je répliquer des datasets chiffrés en toute sécurité ?

Oui, mais « sécurisé » inclut la gestion des clés. Décidez si le DR doit avoir les clés chargées par défaut. Beaucoup d’environnements laissent les clés indisponibles
et utilisent une procédure break‑glass. Dans tous les cas, testez le chargement des clés et le montage.

5) Pourquoi les incrémentaux gonflent‑ils parfois ?

Causes courantes : churn important (bases de données, images VM), erreurs de rétention (conserver d’anciens snapshots épingle des blocs modifiés),
ou un changement de workload (par ex. un nouveau répertoire de cache). Utilisez zfs send -nPv pour mesurer avant d’envoyer.

6) Qu’est‑ce qui casse le plus souvent la réplication incrémentale ?

Les snapshots communs manquants. Généralement causés par un prune sur le récepteur, une suppression manuelle de snapshot, ou un nommage/politiques non alignés.
Protégez la fenêtre du snapshot de base.

7) Les scrubs sont‑ils nécessaires sur le pool DR ?

Si vous tenez à vos données, oui. La réplication peut copier fidèlement une corruption si elle est survenue avant le snapshot, et les disques peuvent pourrir silencieusement.
Les résultats de scrub sont la preuve que la réplique peut se relire.

8) Comment savoir si le récepteur est le goulot ?

Vérifiez les IO du pool avec zpool iostat -v pendant le receive, et observez la latence (via vos métriques OS).
Si le réseau n’est pas plein mais que les écritures sont lentes et que les disques sont saturés, le récepteur est votre limite.

9) Est‑ce acceptable de compresser le flux d’envoi ?

Les streams ZFS reflètent déjà la compression du dataset ; une compression externe supplémentaire aide rarement et peut consommer du CPU.
Mesurez. Si le CPU est saturé sur émetteur/récepteur, vous manquerez le RPO même sur un lien généreux.

10) Dois‑je répliquer les propriétés ?

Répliquez ce qui importe pour la correction et les performances. Puis auditez‑le.
Si vous divergez intentionnellement sur le DR (comme canmount), imposez cette divergence explicitement pour éviter la dérive accidentelle.

Prochaines étapes réalisables cette semaine

  1. Implémentez un contrôle RPO par dataset. Scriptez‑le si nécessaire : comparez les horodatages des snapshots les plus récents sur émetteur et récepteur.
    Alertez quand la politique est dépassée.
  2. Faites un drill de restauration. Choisissez un dataset, clonez le snapshot le plus récent sur le DR, montez‑le et validez au niveau applicatif.
    Mesurez le temps. Notez chaque étape que vous avez dû « retenir ».
  3. Auditez la dérive de périmètre. Énumérez récursivement les datasets sur l’émetteur et confirmez leur existence sur le récepteur.
    Si vous découvrez des enfants manquants, traitez‑le comme un incident réel.
  4. Faites des jetons de reprise une priorité. Si vous avez des liens peu fiables, ne pas gérer les jetons, c’est choisir la douleur.
    Alertez sur les jetons de longue durée et construisez un workflow de reprise sûr.
  5. Alignez la rétention. Assurez‑vous que le prune du récepteur ne peut pas supprimer les snapshots nécessaires comme bases incrémentales.
    Utilisez des holds quand approprié et rendez les « full sends silencieux » socialement inacceptables.
  6. Décidez comment fonctionne le chiffrement en DR. Qui peut charger les clés ? Comment ? Sous quelle approbation ? Entraînez‑vous.

L’objectif n’est pas d’avoir une réplication qui « tourne ». L’objectif est d’avoir une réplication que vous pouvez prouver récupérable,
et un chemin de restauration qui fonctionne quand vous êtes fatigué, stressé et observé.
Voilà ce que doit être « la réplique que vous croyiez avoir » : pas une croyance, mais une capacité démontrée.

← Précédent
La politique de mise à jour qui empêche les ruptures surprises
Suivant →
Paquets Linux : stratégie de mise à niveau sûre sans casser la production

Laisser un commentaire