Du RAID 1 à ZFS – Retour d’expérience d’une migration de 20 heures

Disclaimer et rappel

  • Bien que cela soit en partie mon métier, je suis loin d’être un expert en tout. Ce blog est l’occasion d’expérimenter et de tester des choses, pas de faire référence en la matière ;
  • Une fois rédigé, je me suis appuyé sur l’IA afin d’améliorer sa qualité ;
  • Les retours constructifs sont les bienvenus.

Bonne lecture

Introduction

Comme vous le savez, ou ne le savez probablement pas, je possède un serveur HPE ProLiant MicroServer Gen8 acheté en 2016. Au fil de ces années, j’ai amélioré les performances du serveur en ajoutant un SSD, changé le processeur, ajouté une carte graphique Nvidia Quadro P600, ajouté de la mémoire RAM ECC et équipé de 4 disques durs RED Western Digital de 4 To. Un de mes disques a lâché il y a quelques années et j’ai reconfiguré le tout de façon à avoir du RAID 1 sur 3 disques. Cela signifie que sur les 12 To d’espace, je n’en ai que 4 de disponibles (3.7 utilisables factuellement).

Avec le stockage des photos et vidéos de la famille, l’espace disque se consomme. Au mois de janvier 2026, je suis arrivé à 2 To de disque utilisé sur les 4 To que j’ai à disposition. Je me suis donc dit que j’allais devoir augmenter l’espace disque disponible ainsi que de repasser à 4 disques utilisés afin d’éviter de saturer les disques, ce qui aurait pour effet d’accélérer leur défaillance. C’est cette aventure que je vais vous raconter aujourd’hui.

Au commencement était la défaillance

Lorsque je me suis remis à travailler sur mon NAS, en 2021 ou 2022 je ne sais plus, la mémoire n’est plus ce qu’elle était à mon âge, je me suis aperçu que les opérations de lecture/écriture sur les 4 disques durs RED Western Digital de 4 To étaient lentes. Les disques étaient en raid 6.

https://upload.wikimedia.org/wikipedia/commons/7/70/RAID_6.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original&uselang=fr

En investiguant un peu plus, je me suis rendu compte que pour un disque, les indicateurs de dégradation remontés par le protocole SMART n’étaient pas bons. Globalement, beaucoup de secteurs réattribués. Fort de cette découverte, et soucieux de ne pas perdre de données, je décide de basculer mes 3 disques restants en RAID 1. J’avais alors peu de données à l’époque, je fais une copie sur un disque externe puis je crée un raid 1 avec les 3 disques restants.

https://thumb.wikimedia.org/wikipedia/commons/thumb/b/b7/RAID_1.svg/960px-RAID_1.svg.png?utm_source=fr.wikipedia.org&utm_campaign=imageinfo&utm_content=thumbnail

Avec 3 disques en RAID 1, cela signifie qu’une donnée copiée sur un disque, est copiée également sur les deux autres. Cela permet de conserver la donnée malgré la défaillance de 2 disques, mais avec pour inconvénient la perte de 66 % de l’espace de l’espace de stockage disponible. En termes de performance, on gagne en lecture, mais on perd un peu en écriture.

Le temps passe, et avec lui les disques se remplissent

La vie faisant, et le stockage de photos et de vidéos familles aussi, les 4 To de disques se remplissent. Au début de l’année 2026, j’arrive à un total de 2.5 To de données utilisées sur les 3.7 To disponibles. Rien d’alarmant, mais si cela continue sur cette lancée, je vais me retrouver avec plus aucun espace de disponible.

Vous le savez probablement, mais il est recommandé d’avoir 10% à 15% d’espace libre, ce qui fait environ 400 Go pour un disque de 4 To. Avec cette information, cela signifie que j’utilise 75% de l’espace disque à ma disposition, et qu’il me reste 800 Go de libre. Je prends alors la décision d’augmenter l’espace disponible même si je ne sais pas encore comment.

Première étape, acquérir de nouveaux disques

Mon serveur peut accueillir jusqu’à 4 disques durs, je me suis dit que cela pourrait être une bonne idée d’avoir un disque de rechange disponible pour pouvoir remplacer immédiatement un disque défaillant. En ayant avant un disque à disposition, cela me permet d’avoir le temps d’acheter un nouveau disque à un prix abordable et de ne pas prendre le risque qu’un deuxième disque défaille avec pour conséquence la perte des données.

J’ai donc commencé à chercher deux disques du même modèle, le RED, de la marque Western Digital. Avec la merdification qui se répand à vitesse grand V, j’ai pris le temps d’identifier le bon modèle. Il faut savoir que même si les disques sont appelés RED, ils n’ont pas les mêmes caractéristiques. Il faut privilégier le modèle WD40EFRX et éviter le modèle WD40EFAX pour les NAS.

Les WD40EFRX utilisent la technologie CMR (Conventional Magnetic Recording), tandis que les WD40EFAX utilisent la technologie SMR (Shingled Magnetic Recording), qui superpose les pistes et a pour conséquence de ralentir fortement lors d’opérations d’écritures intenses comme par exemple lors de la reconstruction d’un RAID. Cela peut entraîner des performances très faibles et des temps de reconstruction particulièrement longs.

J’ai repris ma recherche en cherchant spécifiquement le bon modèle et les moins chers que j’ai trouvé neuf étaient à 190 € pièce, ce qui me faisait quasiment 400 euros pour deux disques 🤯, beaucoup trop cher pour moi. Je me suis donc tourné sur le marché de l’occasion et j’ai regardé sur Leboncoin. Après quelques semaines à chercher, j’ai trouvé les deux disques pour 150€, soit 75€ pièce, un bon prix. Pour avoir de tels prix, les disques avaient déjà fonctionné pendant 486 jours, soit un peu plus d’un an. J’ai pris le temps d’y réfléchir, de m’assurer que les valeurs SMART étaient excellentes et je les ai achetés. Après tout, l’occasion reste mieux pour la planète, le prix est très intéressant et j’avais deux disques pour le prix d’un neuf.

Quel système raid logiciel choisir ?

Maintenant que l’on a les disques, la question à un million d’euros : j’ai 4 disques de 4to, quel est le meilleur système raid logiciel ? J’ai le choix entre :

  • Raid 10 avec mdadm
  • Raid 6 avec mdadm
  • Btrfs que je ne connais pas
  • ZFS que je ne connais pas

Le meilleur raid logiciel est celui qui répond le mieux au besoin. On va donc commencer par identifier les critères et leurs importances :

  • 1er critère : l’intégrité de la donnée. Cela signifie la présence de fonctionnalités d’analyse et de correction de la corruption ainsi qu’une bonne tolérance à la panne.
  • 2e critère : la performance. Autant en lecture/écriture qu’en usage CPU et RAM. J’ai notamment boosté le serveur avec 16 Go de Ram et un processeur plus performant pour ne pas avoir à l’attendre.
  • 3e critère : les fonctionnalités. Je pense notamment aux snapshots, qui peuvent s’avérer intéressants avec mes vms et conteneurs, potentiellement la compression.

Une fois établie, on peut voir que ces critères excluent le RAID 10 et RAID 6 avec mdadm, car il n’intègre pas les fonctionnalités de détection et correction de la corruption. Il me reste donc Btrfs et ZFS à analyser, car ils possèdent ces fonctionnalités. En faisant mes recherches, je suis tombé sur cet excellent article publié sur le site de shpv.fr qui présente les différences entre ZFS et Btrfs. Je vous copie la conclusion de l’article :

Choix Rapide par Scénario

Choisir Btrfs si :

  • ✓ Desktop / Laptop Linux
  • ✓ Performance critique (IOPS, latency)
  • ✓ Intégration kernel native importante
  • ✓ RAM limitée (moins de 16GB)
  • ✓ Snapshots occasionnels (moins de 50)
  • ✓ NAS personnel (Synology)

Choisir ZFS si :

  • ✓ Serveur production critique
  • ✓ Intégrité données absolue requise
  • ✓ RAID5/6 nécessaire (RAID-Z)
  • ✓ Nombreux snapshots (>100)
  • ✓ Encryption par dataset
  • ✓ Enterprise NAS (TrueNAS, Proxmox)

Évolutions Futures

Btrfs Roadmap 2026-2027

  • RAID5/6 stabilisation (enfin ?)
  • Performance RAID-Z like
  • Amélioration scalabilité snapshots
  • Deduplication native (proposé)

ZFS Roadmap 2026-2027

  • RAID expansion simplifiée
  • Performance optimizations (SIMD)
  • Meilleure intégration systemd
  • Réduction overhead CPU

En lisant cette conclusion, je choisis de m’orienter vers ZFS, car il me semble être plus efficace en ce qui concerne l’intégrité des données, il intègre le chiffrement nativement et est proposé nativement dans Proxmox comme système de fichier.

En termes de consommation RAM, on trouve souvent la recommandation de prévoir environ 1 Go de RAM par To de stockage pour ZFS. Il s’agit toutefois d’une règle empirique, et non d’un prérequis : les besoins réels dépendent de l’utilisation du serveur et des fonctionnalités activées. Avec mes 16 Go de RAM, dont environ 8 Go de disponibles et 8 To d’espace disque utilisable, je disposais donc d’une quantité de mémoire cohérente avec cette recommandation.

Les étapes de migration

Une fois l’architecture choisie, il faut écrire le plan de migration. J’ai donc schématisé l’architecture de départ et d’arrivée puis défini les étapes intermédiaires. En termes d’architecture, cela donne ça :

# Ancienne architecture
    
      ┌─────┴─────┐
      │           │
   raid 1   Disque libre
┌─────┴───┐       │
│    │    │       │
4To 4To 4To      4To


# Nouvelle architecture

        ZFS Pool
           │
     ┌─────┴─────┐
     │           │
   mirror      mirror
   │   │       │   │
  4To 4To     4To 4To

Les différentes étapes de la migration :

  1. Identification des disques et vérification de l’espace disponible
  2. Création du pool ZFS sur le disque libre
  3. Copie des données avec rsync du RAID 1 / 3 disques → le disque libre
  4. Vérification des données (que je n’ai pas exécuté)
  5. Suppression d’un disque sur le RAID 1 / 3 disques avec nettoyage des en-têtes
  6. Ajout du disque au pool ZFS (Passage de 1 à 2 disques)
  7. Suppression des 2 autres disques du RAID 1
  8. Création du second miroir et intégration au pool ZFS
  9. Vérification des données (que je n’ai pas exécuté)

Rédaction et exécution du script (On serre les dents)

Je me suis appuyé sur ChatGPT pour rédiger le script dans son intégralité. Après plusieurs itérations, le script généré correspondait à ce que je voulais. J’ai pris le temps de le relire plusieurs fois attentivement pour corriger les dernières erreurs, dont une erreur de nom de variable, une mauvaise syntaxe pour une fonction, des commandes de vérifications superflues et coûteuses en temps et I/O et une sauvegarde de la clé dans un fichier alors que je voulais qu’elle soit demandée lors du montage du pool.

La durée totale d’exécution du script a été de 20 heures dont 5 heures pour la copie des données et 15 heures 🤯 pour l’intégration du second disque. J’ai été assez surpris par ces durées, je m’attendais à de bien meilleures performances avec des disques supposés atteindre des vitesses d’écriture de 120 à 150 Mo/s. Les recherches que j’ai faites ne m’ont pas permis de déterminer la cause de cette lenteur et d’accélérer le temps de traitement, j’ai donc attendu, attendu et attendu.

Par contre, la création du second miroir a été instantanée. L’intégralité de mes données se trouvait en effet déjà sur le premier miroir. Je pensais que ZFS allait répartir automatiquement les données entre les deux miroirs afin de mieux exploiter l’espace disponible et les performances du pool. Ce n’est finalement pas ce qui s’est produit : l’ajout du second miroir n’a pas entraîné de déplacement automatique des données existantes. Le premier miroir contient donc toujours l’essentiel de mes données, tandis que le second dispose de beaucoup plus d’espace libre.

Après quelques recherches, il est possible de rééquilibrer la répartition en réécrivant les données, mais cela aurait nécessité une opération supplémentaire et un temps de traitement important. J’ai donc choisi de ne pas le faire, compte tenu de la durée déjà importante de la migration et du gain limité dans mon cas.

Les nouvelles données écrites dans le pool pourront, elles, être réparties entre les différents vdevs en fonction du fonctionnement de ZFS. Je surveillerai donc l’évolution de la répartition au fil du temps plutôt que de lancer volontairement une nouvelle migration des données existantes.

Vous pourrez trouver ci-dessous le script complet anonymisé :

Afficher le script


#!/bin/bash

set -Eeuo pipefail

###############################################################################
# PARAMÈTRES
###############################################################################

ZFS_PASSPHRASE='A_MODIFIER_AVANT_EXECUTION'

POOL='tank'
DATASET='tank/data'

OLD_RAID='/dev/md0'
OLD_MOUNT='/mnt/encrypted_raid'

###############################################################################
# IDENTIFIANTS PERSISTANTS
###############################################################################

DISK_FREE='/dev/disk/by-id/ata-WDC_WD40EFRX-68WT0N0_WD-XXXXX'

DISK_RAID_1='/dev/disk/by-id/ata-WDC_WD40EFRX-68WT0N0_WD-XXXXX'

DISK_RAID_2='/dev/disk/by-id/ata-WDC_WD40EFRX-68WT0N0_WD-XXXXX'

DISK_RAID_3='/dev/disk/by-id/ata-WDC_WD40EFRX-68WT0N0_WD-XXXXX'

SYSTEM_DISK='/dev/disk/by-id/ata-XXXXX'

###############################################################################
# FICHIER DE CLÉ
###############################################################################

ZFS_KEYFILE='/root/zfs-key'

###############################################################################
# LOG
###############################################################################

LOGFILE='/var/log/migration-zfs.log'

exec > >(tee -a "$LOGFILE") 2>&1

###############################################################################
# GESTION ERREURS
###############################################################################

trap '
echo
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "ERREUR"
echo "Ligne : $LINENO"
echo "Commande : $BASH_COMMAND"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo
exit 1
' ERR

###############################################################################
# FONCTIONS
###############################################################################

die()
{
    echo
    echo "ERREUR : $1"
    exit 1
}

###############################################################################
# ROOT
###############################################################################

[[ $EUID -eq 0 ]] || die "Le script doit être exécuté en root."

###############################################################################
# PASSPHRASE
###############################################################################

[[ "$ZFS_PASSPHRASE" != 'A_MODIFIER_AVANT_EXECUTION' ]] \
    || die "Modifiez ZFS_PASSPHRASE avant d'exécuter le script."

[[ -n "$ZFS_PASSPHRASE" ]] \
    || die "La passphrase ZFS est vide."

###############################################################################
# AFFICHAGE
###############################################################################

echo
echo "============================================================"
echo " MIGRATION RAID1 -> ZFS"
echo "============================================================"
echo
date
echo

###############################################################################
# VÉRIFICATION DES IDENTIFIANTS
###############################################################################

echo "Vérification des disques..."

for disk in \
    "$DISK_FREE" \
    "$DISK_RAID_1" \
    "$DISK_RAID_2" \
    "$DISK_RAID_3" \
    "$SYSTEM_DISK"
do

    [[ -e "$disk" ]] || die "Disque introuvable : $disk"

done

###############################################################################
# VÉRIFICATION MODÈLES
###############################################################################

echo
echo "Disque libre :"
lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE,FSTYPE,MOUNTPOINTS "$DISK_FREE"

echo
echo "Disque RAID 1 :"
lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE,FSTYPE,MOUNTPOINTS "$DISK_RAID_1"

echo
echo "Disque RAID 2 :"
lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE,FSTYPE,MOUNTPOINTS "$DISK_RAID_2"

echo
echo "Disque RAID 3 :"
lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE,FSTYPE,MOUNTPOINTS "$DISK_RAID_3"

echo
echo "Disque système :"
lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE,FSTYPE,MOUNTPOINTS "$SYSTEM_DISK"

###############################################################################
# PROTECTION SSD
###############################################################################

SYSTEM_REAL=$(readlink -f "$SYSTEM_DISK")

for disk in \
    "$DISK_FREE" \
    "$DISK_RAID_1" \
    "$DISK_RAID_2" \
    "$DISK_RAID_3"
do

    REAL=$(readlink -f "$disk")

    [[ "$REAL" != "$SYSTEM_REAL" ]] \
        || die "PROTECTION : un disque de données correspond au SSD système."

done

###############################################################################
# VÉRIFICATION TAILLE
###############################################################################

for disk in \
    "$DISK_FREE" \
    "$DISK_RAID_1" \
    "$DISK_RAID_2" \
    "$DISK_RAID_3"
do

    SIZE=$(blockdev --getsize64 "$disk")

    # Environ 4 To minimum
    MIN_SIZE=$((3 * 1024 * 1024 * 1024 * 1024))

    [[ "$SIZE" -gt "$MIN_SIZE" ]] \
        || die "Le disque $disk ne semble pas être un disque de 4 To."

done

###############################################################################
# VÉRIFICATION RAID
###############################################################################

echo
echo "============================================================"
echo " ÉTAT DU RAID ACTUEL"
echo "============================================================"

cat /proc/mdstat

echo
mdadm --detail "$OLD_RAID"

###############################################################################
# VÉRIFICATION MEMBRES RAID
###############################################################################

mdadm --detail "$OLD_RAID" \
    | grep -q "$DISK_RAID_1" \
    || true

###############################################################################
# VÉRIFICATION MONTAGE
###############################################################################

mountpoint -q "$OLD_MOUNT" \
    || die "$OLD_MOUNT n'est pas monté."

echo
echo "Données actuelles :"

df -hT "$OLD_MOUNT"

###############################################################################
# INSTALLATION ZFS
###############################################################################

echo
echo "============================================================"
echo " ZFS"
echo "============================================================"

if ! command -v zpool >/dev/null 2>&1
then

    apt update
    apt install -y zfsutils-linux

fi

modprobe zfs

###############################################################################
# VÉRIFICATION POOL INEXISTANT
###############################################################################

if zpool list "$POOL" >/dev/null 2>&1
then
    die "Le pool $POOL existe déjà."
fi

###############################################################################
# VÉRIFICATION DISQUE LIBRE
###############################################################################

echo
echo "Vérification du disque libre..."

if findmnt "$DISK_FREE" >/dev/null 2>&1
then
    die "$DISK_FREE est monté."
fi

if lsblk "$DISK_FREE" -o FSTYPE \
    | grep -v '^FSTYPE$' \
    | grep -q .
then
    echo "Le disque libre contient actuellement des signatures."

fi

###############################################################################
# NETTOYAGE DISQUE LIBRE
###############################################################################

echo
echo "============================================================"
echo " PRÉPARATION DU DISQUE LIBRE"
echo "============================================================"

wipefs -a "$DISK_FREE"

partprobe "$DISK_FREE" || true

###############################################################################
# CRÉATION POOL TEMPORAIRE
###############################################################################

echo
echo "============================================================"
echo " CRÉATION POOL ZFS"
echo "============================================================"

zpool create \
    -f \
    -o ashift=12 \
    "$POOL" \
    "$DISK_FREE"

###############################################################################
# CONFIGURATION ZFS
###############################################################################

echo
echo "Configuration ZFS..."

zfs set dedup=off "$POOL"
zfs set compression=lz4 "$POOL"
zfs set atime=off "$POOL"
zfs set xattr=sa "$POOL"
zfs set dnodesize=auto "$POOL"
zfs set sync=standard "$POOL"

###############################################################################
# CRÉATION CLÉ
###############################################################################

echo
echo "Création du fichier de clé..."

umask 077

printf '%s' "$ZFS_PASSPHRASE" > "$ZFS_KEYFILE"

chmod 600 "$ZFS_KEYFILE"

###############################################################################
# DATASET CHIFFRÉ
###############################################################################

echo
echo "============================================================"
echo " CRÉATION DATASET CHIFFRÉ"
echo "============================================================"

zfs create \
    -o encryption=aes-256-gcm \
    -o keyformat=passphrase \
    -o keylocation="file://$ZFS_KEYFILE" \
    "$DATASET"

###############################################################################
# VÉRIFICATION
###############################################################################

echo
echo "Configuration du dataset :"

zfs get encryption,keyformat,keylocation,compression,dedup,atime,xattr,dnodesize,sync "$DATASET"

###############################################################################
# TEST
###############################################################################

echo
echo "Test du stockage..."

TEST_FILE="/tank/data/.zfs-migration-test"

echo "ZFS migration test" > "$TEST_FILE"

sync

cat "$TEST_FILE"

rm "$TEST_FILE"

###############################################################################
# ARRÊT SERVICES
###############################################################################

echo
echo "============================================================"
echo " ARRÊT SERVICES"
echo "============================================================"

pct stop xx1
pct stop xx2
pct stop xx3
pct stop xx4
qm stop xx1

###############################################################################
# PREMIÈRE COPIE
###############################################################################

echo
echo "============================================================"
echo " PREMIÈRE COPIE"
echo "============================================================"

rsync \
    -aHAX \
    --numeric-ids \
    --info=progress2 \
    "$OLD_MOUNT/" \
    "/tank/data/"


###############################################################################
# VÉRIFICATION MONTAGE
###############################################################################

echo
echo "Vérification des processus utilisant $OLD_MOUNT..."

if fuser -m "$OLD_MOUNT" >/dev/null 2>&1
then

    echo
    fuser -vm "$OLD_MOUNT"

    die "Des processus utilisent encore $OLD_MOUNT."

fi

###############################################################################
# SYNCHRONISATION FINALE
###############################################################################

echo
echo "============================================================"
echo " SYNCHRONISATION FINALE"
echo "============================================================"

rsync \
    -aHAX \
    --numeric-ids \
    --delete \
    --info=progress2 \
    "$OLD_MOUNT/" \
    "/tank/data/"

###############################################################################
# VÉRIFICATION FINALE RSYNC
###############################################################################
# 
# echo
# echo "Contrôle final :"
# 
# rsync \
#     -aHAXn \
#     --numeric-ids \
#     --delete \
#     "$OLD_MOUNT/" \
#     "/tank/data/"

###############################################################################
# SYNCHRONISATION DISQUES
###############################################################################

sync

###############################################################################
# DÉMONTAGE
###############################################################################

echo
echo "============================================================"
echo " ARRÊT ANCIEN STOCKAGE"
echo "============================================================"

umount "$OLD_MOUNT"

###############################################################################
# LVM
###############################################################################

echo
echo "Désactivation LVM..."

vgchange -an vg_raid

###############################################################################
# LUKS
###############################################################################

echo
echo "Fermeture LUKS..."

if cryptsetup status raid_crypted >/dev/null 2>&1
then

    cryptsetup close raid_crypted

fi

###############################################################################
# RAID
###############################################################################

echo
echo "Arrêt md0..."

mdadm --stop "$OLD_RAID"

###############################################################################
# VÉRIFICATION RAID ARRÊTÉ
###############################################################################

if [[ -e "$OLD_RAID" ]]
then

    echo
    echo "ATTENTION : $OLD_RAID existe encore."

fi

###############################################################################
# NETTOYAGE ANCIENS DISQUES
###############################################################################

echo
echo "============================================================"
echo " NETTOYAGE DES 3 DISQUES DE L'ANCIEN RAID"
echo "============================================================"

for disk in \
    "$DISK_RAID_1" \
    "$DISK_RAID_2" \
    "$DISK_RAID_3"
do

    echo
    echo "Nettoyage : $disk"
# 
    wipefs -a "$disk"

    partprobe "$disk" || true

done

###############################################################################
# PREMIER MIRROR
###############################################################################

echo
echo "============================================================"
echo " PREMIER MIRROR"
echo "============================================================"

echo
echo "Création :"
echo
echo "    $DISK_FREE"
echo "    $DISK_RAID_1"
echo

zpool attach \
    "$POOL" \
    "$DISK_FREE" \
    "$DISK_RAID_1"

###############################################################################
# ATTENTE RESILVER
###############################################################################

echo
echo "Attente du resilver..."

while zpool status "$POOL" \
    | grep -q "resilver in progress"
do

    zpool status "$POOL"

    sleep 30

done

###############################################################################
# CONTRÔLE PREMIER MIRROR
###############################################################################

echo
echo "============================================================"
echo " PREMIER MIRROR TERMINÉ"
echo "============================================================"

zpool status -v "$POOL"

###############################################################################
# SCRUB PREMIER MIRROR
###############################################################################

# echo
# echo "Lancement du scrub..."

# zpool scrub "$POOL"

# while zpool status "$POOL" \
#     | grep -q "scrub in progress"
# do

#     zpool status "$POOL"

#     sleep 60

# done

###############################################################################
# CONTRÔLE SCRUB
###############################################################################

zpool status -v "$POOL"

###############################################################################
# SECOND MIRROR
###############################################################################

echo
echo "============================================================"
echo " SECOND MIRROR"
echo "============================================================"

echo
echo "Création :"
echo
echo "    $DISK_RAID_2"
echo "    $DISK_RAID_3"
echo

zpool add \
    "$POOL" \
    mirror \
    "$DISK_RAID_2" \
    "$DISK_RAID_3"

###############################################################################
# VÉRIFICATION FINALE
###############################################################################

echo
echo "============================================================"
echo " VÉRIFICATION FINALE"
echo "============================================================"

echo
echo "----- ZPOOL STATUS -----"

zpool status -v "$POOL"

echo
echo "----- ZPOOL LIST -----"

zpool list "$POOL"

echo
echo "----- ZFS LIST -----"

zfs list

echo
echo "----- PROPRIÉTÉS -----"

zfs get encryption,keyformat,keylocation,compression,dedup,atime,xattr,dnodesize,sync "$DATASET"

###############################################################################
# TEST CLÉ
###############################################################################

echo
echo "----- TEST CHIFFREMENT -----"

zfs unload-key "$DATASET"

zfs load-key "$DATASET"

zfs mount "$DATASET" || true

echo
echo "Clé ZFS correctement rechargée."

###############################################################################
# TEST DONNÉES
###############################################################################

echo
echo "----- TEST DONNÉES -----"

ls -lah "/tank/data" | head -20

###############################################################################
# FIN
###############################################################################
  

Diagnostic de la bête, est-ce que tout va bien ?

Cela fait maintenant 1 mois que j’ai effectué la migration. Pour l’instant, tout va bien. 🥳 Afin de m’assurer de la bonne santé du pool ZFS, j’utilise de temps en temps ces commandes.

La commande zpool iostat -v affiche les statistiques d’I/O du pool ZFS et de chacun de ses disques/vdevs : lectures, écritures, bande passante, taille des disques. Le retour dans ma situation ressemble à ça :

zpool iostat -v
                                                capacity     operations     bandwidth 
pool                                          alloc   free   read  write   read  write
--------------------------------------------  -----  -----  -----  -----  -----  -----
tank                                          2.48T  4.77T     34     21  19.9M  10.1M
  mirror-0                                    2.47T  1.16T     39     22  23.2M  11.7M
    ata-WDC_WD40EFRX-XXXXX1      -      -     22      6  12.4M  4.99M
    ata-WDC_WD40EFRX-XXXXX2      -      -     13     14  8.68M  5.84M
  mirror-1                                    14.6G  3.61T      0      2  64.2K   172K
    ata-WDC_WD40EFRX-XXXXX3      -      -      0      1  31.5K  86.0K
    ata-WDC_WD40EFRX-XXXXX4      -      -      0      1  32.6K  86.0K
--------------------------------------------  -----  -----  -----  -----  -----  -----

La commande zpool status affiche l’état de santé de ton pool ZFS : disques présents, état ONLINE/DEGRADED/FAULTED, erreurs, scrub/reconstruction. Dans ma situation, on voit que j’ai interrompu un scrub, car je l’ai jugé non nécessaire.

zpool status

  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 07:50:46 with 0 errors on Sun Sep 13 08:14:48 2026
config:

        NAME                                          STATE     READ WRITE CKSUM
        tank                                          ONLINE       0     0     0
          mirror-0                                    ONLINE       0     0     0
            ata-WDC_WD40EFRX-XXXXX1                   ONLINE       0     0     0
            ata-WDC_WD40EFRX-XXXXX2                   ONLINE       0     0     0
          mirror-1                                    ONLINE       0     0     0
            ata-WDC_WD40EFRX-XXXXX3                   ONLINE       0     0     0
            ata-WDC_WD40EFRX-XXXXX4                   ONLINE       0     0     0

errors: No known data errors

ZFS utilise la RAM pour mettre en cache des données, ce qui a pour conséquence d’accélérer les lectures et de gérer les écritures. La commande cat /proc/spl/kstat/zfs/arcstats | grep -E ‘^(size|c|c_min|c_max)’ | awk ‘{printf « %-30s %12.2f GiB\n », $1, $3/1024/1024/1024}’ permet d’afficher la consommation de mémoire par zfs. On peut voir qu’avec environ 2.5 To d’utilisé, je consomme 3.63 Go de mémoire RAM. Loin de ce que j’avais lu d’environ 1 Go / To de disque. A voir si cela évolue en fonction de l’utilisation du volume disponible.

cat /proc/spl/kstat/zfs/arcstats | grep -E '^(size|c|c_min|c_max)' | awk '{printf "%-30s %12.2f GiB\n", $1, $3/1024/1024/1024}'
c                                      3.63 GiB
c_min                                  0.49 GiB
c_max                                  8.00 GiB
size                                   2.31 GiB
compressed_size                        2.03 GiB
cached_only_in_progress                0.00 GiB

free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi       6.8Gi       5.5Gi       205Mi       3.8Gi       8.7Gi
Swap:           15Gi       1.0Gi        15Gi

Conclusion

Le projet s’est étalé sur plusieurs mois, à raison de quelques heures de-ci, de-là. L’objectif était simple : augmenter mon volume disponible tout en profitant de cette migration pour découvrir une nouvelle technologie si cela s’avérait nécessaire.

Au final, l’objectif est atteint. L’espace disponible a augmenté avec mes quatre disques regroupés au sein d’un même pool ZFS et j’ai pu expérimenter une technologie que je ne connaissais pas auparavant. Même si la migration ne s’est pas déroulée aussi rapidement que je l’espérais, cela fait aussi partie de l’intérêt de ce type de projet : on apprend autant de ce qui ne se passe pas comme prévu que du reste.

Après un mois de fonctionnement sans problème et une consommation en RAM plus faible que prévu, je considère cette migration comme terminée. Il ne reste maintenant plus qu’à laisser ZFS faire son travail et à surveiller que tout va bien. 🤞

Bibliographie

Quelques articles de blog qui m’ont aidé au cours de cette migration en complément de ceux cités au cours de l’article :


Commentaires

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *