ZFS

De UnixManiax
Aller à la navigation Aller à la recherche
La version imprimable n’est plus prise en charge et peut comporter des erreurs de génération. Veuillez mettre à jour les signets de votre navigateur et utiliser à la place la fonction d’impression par défaut de celui-ci.


Présentation

ZFS est un système de fichiers développé par Sun Microsystems pour remplacer UFS. ZFS est également un gestionnaire de volumes logiques et de raid logiciel. Il est donc le remplaçant du couple UFS+SVM (Solaris Volume Manager ou SDS=Solstice Disk Suite pour les anciens Smiley-langue.gif). C'est donc un concurrent de LVM+JFS2 d'AIX ou mdtools+LVM2+Ext4 de linux. En effet, ce que linux gère avec trois outils différents (raid logiciel+gestionnaire de volumes+filesystem), Solaris le gère maintenant avec un seul : ZFS. Je ne dit pas ça pour dire du mal de linux, que j'utilise au quotidien, mais là, Solaris est clairement en avance.

ZFS s'appuie, comme ses concurrents, sur des partitions de disques dur (difficile de faire autrement...). Dans le langage ZFS, une partition dont il a le contrôle s'appelle un vDev (virtual device), c'est l'équivalent d'un PV en LVM. Par dessus, on va créer des zpools, équivalent des groupes en LVM. C'est au moment ou on créé le zpool qu'on va également définir le niveau de raid. Comme on le verra plus tard, il suffit de lui indiquer le niveau de raid souhaité et les partitions qu'il doit prendre en compte, et il fait tout tout seul. On peut même lui ajouter à chaud des disques pour agrandir les volumes. Ensuite, on va créer les filesystems (FS). Et là, tout devient très différent de ce qu'on a l'habitude de voir, car on ne précise pas la taille du FS. Tous les FS créés dans le zpool se partagent l'espace disque automatiquement, un peu comme des répertoires se partagent l'espace disque sur une partition. Tout se fait de manière dynamique extrêmement rapidement. Les méta-données sont également allouées dynamiquement, donc plus besoin de pré-allouer des inodes, donc plus de risque de saturation du nombre d'inodes. Vous allez me dire : "cette méthode est dangereuse car un FS qui grossit trop va remplir tout le zpool et tous les FS vont être bloqués". Je répondrai : "oui et non". Chaque FS créé avec ZFS peut se voir attribuer des quotas et des réservations. Les quotas sont une limite de taille que le FS ne pourra pas dépasser, et les réservations une taille minimum qui lui est garantie. Il est d'ailleurs fortement recommandé d'utiliser ces quotas et réservations pour prévenir tout problème de remplissage incontrôlé. Cette façon de voir les choses est un peu déroutante au début, mais elle est beaucoup plus souple. Il est très rapide de modifier une valeur de quota et de réservation, alors qu'il prend du temps (parfois beaucoup) sous LVM pour modifier la taille d'un volume, puis du FS qui est sur ce volume.

Autre avantage de ZFS : il s'auto répare. ZFS créé des sommes de contrôle de ses données et méta-données et est capable de détecter et réparer les erreurs. Dans un raid, si une donnée est perdue, ZFS va la récupérer sur une autre branche du raid et remettre la bonne valeur. Tout ça est géré automatiquement en arrière plan par le système, aucune intervention humaine n'est nécessaire.

En cas de coupure de courant, pas de problème : ZFS est un système de fichiers transactionnel qui garanti en permanence la cohérence des données sur les disques. C'est à la fois plus rapide et plus efficace que la journalisation. Le principe de transaction est très utilisé dans les bases de données. Plus de détails ici : http://fr.wikipedia.org/wiki/Transaction_informatique.

ZFS permet également de faire très rapidement des snapshots et des clones de FS. Les FS peuvent être compressés.

Au quotidien, ZFS fait gagner beaucoup de temps à l'administrateur. Non seulement les commandes sont moins nombreuses à taper, et la gestion des volumes simplifiée, mais les montages se font tout automatiquement et il n'est plus nécessaire de remplir la vfstab.

Pour finir avec cette présentation, parlons de chiffres. ZFS est un système de fichiers 128 bits. Ceci lui permet d'avoir des FS d'une taille maximale de 256 quadrillions de zetta-octets. J'imagine que cela ne vous parle pas trop, alors précisons : un zetta-octet (Zo) est égal à 1 milliard de To, et un quadrillion est égal à un million de milliards de milliards. Donc pour résumer, la taille maximale d'un FS ZFS est de 256 millions de milliards de milliards de To ! Autant dire qu'on est tranquille pour quelques temps... Quant au nombre maximal de fichiers que peut contenir un répertoire, il est de 256 trillions, soit 256 milliards de milliards. Bref, ça a été un peu mieux pensé que le FAT32... Smiley-dents.gif


Les bases de ZFS par l'exemple

Voici quelques petits exemples pour pouvoir utiliser rapidement ZFS. Nous verrons les détails plus tard.


Les zpools

On a un disque c0t2d0 qui possède deux partitions de 20Go : c0t2d0s0 et c0t2d0s1.

Créons un datapool sur chacune des partitions et visualisons le résultat :

# zpool create testpool c0t2d0s0
# zpool create testpool2 c0t2d0s1
# zpool list
NAME        SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
testpool   19.9G  95.5K  19.9G     0%  ONLINE  -
testpool2  19.9G  95.5K  19.9G     0%  ONLINE  -
#
# zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
testpool     72K  19.6G    21K  /testpool
testpool2    72K  19.6G    21K  /testpool2


Les systèmes de fichiers

Systèmes de fichiers simples, quotas et réservations

On va maintenant créer deux systèmes de fichiers simples dans testpool :

# zfs create testpool/test
# zfs create testpool/test/foo
# zfs list
NAME                USED  AVAIL  REFER  MOUNTPOINT
testpool            130K  19.6G    22K  /testpool
testpool/test        42K  19.6G    21K  /testpool/test
testpool/test/foo    21K  19.6G    21K  /testpool/test/foo
testpool2            72K  19.6G    21K  /testpool2

On voit que les filesystems (FS) créés ont la même taille que leur pool. D'ailleurs, il n'y a pas besoin de préciser leur taille. Tous les FS créés se partagent l'espace disponible sur le pool. Cependant, on peut leur affecter des quotas et des réservations (ou les deux à la fois). Les quotas servent à limiter la taille maximale utilisable par un FS, et la réservation sert à garantir au FS un espace minimum qui lui sera réservé, pour être sûr que les autres FS ne prendront pas toute la place. On peut également activer la compression sur un FS. Voyons un exemple.

# zfs create -o quota=1g testpool/test/foo2
# zfs create -o reservation=1g -o compression=on testpool/test/foo3
# zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
testpool            1.00G  18.6G    22K  /testpool
testpool/test       1.00G  18.6G    24K  /testpool/test
testpool/test/foo     21K  18.6G    21K  /testpool/test/foo
testpool/test/foo2    21K  1024M    21K  /testpool/test/foo2
testpool/test/foo3    21K  19.6G    21K  /testpool/test/foo3
testpool2             72K  19.6G    21K  /testpool2

On voit que l'espace disponible dans testpool diminue de 1Go, ce qui correspond à la taille réservée à testpool/test/foo3. Par contre, la taille disponible pour ce dernier est toujours de 19,6Go car aucun autre FS n'a réservé d'espace disque. On remarque également que l'espace disponible pour testpool/test/foo2 est de 1024Mo, car c'est le quota qu'on lui a fixé.

La compression activée pour testpool/test/foo3 n'est pas visible avec "zfs list". Pour la voir il faut utiliser "zfs get" qu'on verra plus tard. Ou plus simplement "zfs list -o compression", mais on ne verra plus les autres informations. Pour tout voir : "zfs list -o name,used,avail,refer,mountpoint,compression". Il existe encore d'autres valeurs qu'on peut afficher, mais je vous laisse lire la page man pour les voir, car elles évoluent avec les versions de ZFS.

# zfs list -o compression
COMPRESS
 off
 off
 off
 off
 on
 off
# zfs list -o name,used,avail,refer,mountpoint,compression
NAME                 USED  AVAIL  REFER  MOUNTPOINT           COMPRESS
testpool            1.00G  18.6G    22K  /testpool                 off
testpool/test       1.00G  18.6G    24K  /testpool/test            off
testpool/test/foo     21K  18.6G    21K  /testpool/test/foo        off
testpool/test/foo2    21K  1024M    21K  /testpool/test/foo2       off
testpool/test/foo3    21K  19.6G    21K  /testpool/test/foo3        on
testpool2             72K  19.6G    21K  /testpool2                off

Une remarque importante sur la compression : celle-ci compresse les données à la volée. C'est à dire que les nouveaux fichiers seront compressés, mais les anciens resteront non compressés. Il faut donc penser à la compression avant d'avoir des problèmes d'espace disque ! A noter que les différents benchs que j'ai pu lire montrent que la compression ne fait pas perdre de performance et en fait même gagner dans quelques cas. Ça peut donc être une bonne idée de l'activer dès la création du FS.

Les valeurs de quota et de réservation peuvent se changer à tout moment. Exemple.

# zfs set quota=2g testpool/test/foo2
# zfs set reservation=512m testpool/test/foo2
# zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
testpool            1.50G  18.1G    22K  /testpool
testpool/test       1.50G  18.1G    25K  /testpool/test
testpool/test/foo     21K  18.1G    21K  /testpool/test/foo
testpool/test/foo2    21K  2.00G    21K  /testpool/test/foo2
testpool/test/foo3    21K  19.1G    21K  /testpool/test/foo3
testpool2             72K  19.6G    21K  /testpool2

On remarque les changements de valeur USED et AVAIL qui se répercutent sur les différents FS de testpool. On ne peut pas changer deux valeurs à la fois avec "zfs set", il faut faire plusieurs lignes.

Si on veut supprimer un quota ou une réservation, il faut remplacer la valeur par "none" :

# zfs set quota=none testpool/test/foo2

Points de montage

Par défaut, les FS sont montés dans l'arborescence qui correspond au nom du zfs (par exemple, testpool/test est monté dans /testpool/test) et les répertoires correspondants sont automatiquement créés. Cependant, on peut modifier le point de montage, soit à la création, soit après coup. Exemples.

# zfs create -p -o mountpoint=/data testpool/users/data
# zfs set mountpoint=/testpool/foo2 testpool/test/foo2
# zfs list
NAME                  USED  AVAIL  REFER  MOUNTPOINT
testpool             1.50G  18.1G    24K  /testpool
testpool/test        1.50G  18.1G    25K  /testpool/test
testpool/test/foo      21K  18.1G    21K  /testpool/test/foo
testpool/test/foo2     21K  2.00G    21K  /testpool/foo2
testpool/test/foo3     21K  19.1G    21K  /testpool/test/foo3
testpool/users         42K  18.1G    21K  /testpool/users
testpool/users/data    21K  18.1G    21K  /data
testpool2              72K  19.6G    21K  /testpool2

Et voilà. On remarque au passage l'option "-p" de "zfs create" qui permet, à la manière de "mkdir -p", de créer de manière récursive l'arborescence de testpool/users/data. Sans cette option, il aurait fallu commencer pour faire "zfs create testpool/users" puis "zfs create testpool/users/data".

On peu également ne pas vouloir qu'un FS ou un zpool ne soit pas monté. On peut le préciser avec l'option "mountpoint=none" à la création ou après coup, comme dans l'exemple suivant. A noter que si on le fait après coup, le répertoire de montage sera supprimé au passage.

# zfs set mountpoint=none testpool/test/foo3
# zfs list testpool/test/foo3
NAME                 USED  AVAIL  REFER  MOUNTPOINT
testpool/test/foo3    21K  19.1G    21K  none

A noter que tous les points de montage sont inscrits dans les databases (ou méta données) internes de ZFS, ce qui fait qu'il n'est plus nécessaire de renseigner /etc/vfstab. Les montages seront automatiquement remontés au reboot.

Obtenir des infos sur les FS

Pour obtenir des informations sur les FS, on utilise la commande "zfs get". On obtient la totalité des informations avec "zfs get all". Je ne donnerai pas d'exemple ici, car avec les quelques FS qu'on vient de créer, ça nous affiche déjà 345 lignes d'informations !

Mais on peut limiter l'affichage aux seules informations qui nous intéressent, par exemple les quotas ou la compression. On peut réduire encore plus la sélection en précisant le FS. Exemples.

# zfs get quota
NAME                 PROPERTY  VALUE  SOURCE
testpool             quota     none   default
testpool/test        quota     none   default
testpool/test/foo    quota     none   default
testpool/test/foo2   quota     2G     local
testpool/test/foo3   quota     none   default
testpool/users       quota     none   default
testpool/users/data  quota     none   default
testpool2            quota     none   default
# zfs get compression
NAME                 PROPERTY     VALUE     SOURCE
testpool             compression  off       default
testpool/test        compression  off       default
testpool/test/foo    compression  off       default
testpool/test/foo2   compression  off       default
testpool/test/foo3   compression  on        local
testpool/users       compression  off       default
testpool/users/data  compression  off       default
testpool2            compression  off       default
# zfs get compression testpool/test/foo
NAME               PROPERTY     VALUE     SOURCE
testpool/test/foo  compression  off       default

On peut également utiliser "zfs list" avec les options souhaitées, comme on l'a vu plus haut. Exemple : "zfs list -o name,used,avail,refer,mountpoint,compression".

Suppression de FS

On utilise "zfs destroy".

ATTENTION : cette commande ne demande aucune confirmation !!! A utiliser avec la plus grande précaution donc.

# zfs list
NAME                  USED  AVAIL  REFER  MOUNTPOINT
testpool             1.50G  18.1G    25K  /testpool
testpool/test        1.50G  18.1G    24K  /testpool/test
testpool/test/foo      21K  18.1G    21K  /testpool/test/foo
testpool/test/foo2     21K  2.00G    21K  /testpool/foo2
testpool/test/foo3     21K  19.1G    21K  /testpool/test/foo3
testpool/users         42K  18.1G    21K  /testpool/users
testpool/users/data    21K  18.1G    21K  /data
testpool2              72K  19.6G    21K  /testpool2
# zfs destroy testpool/users/data
# zfs destroy testpool/users
# zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
testpool            1.50G  18.1G    25K  /testpool
testpool/test       1.50G  18.1G    24K  /testpool/test
testpool/test/foo     21K  18.1G    21K  /testpool/test/foo
testpool/test/foo2    21K  2.00G    21K  /testpool/foo2
testpool/test/foo3    21K  19.1G    21K  /testpool/test/foo3
testpool2             72K  19.6G    21K  /testpool2

Et voilà, les deux FS ont été détruits sans sommation !

Pour les pools, on utilise la commande "zpool destroy nom-du-pool" qui est aussi radicale, même si le pool contient des FS ! On peut donc perdre énormément de données en un instant.

Voilà, nous avons vu la plupart des commandes utiles au quotidien pour ZFS. Il reste encore un point important à voir dans le détail avant de se lancer dans l'administration ZFS chez votre patron : la gestion des niveaux de raid avec les zpools. Let's go !


Les zpools dans le détail

Comme nous l'avons vu dans la présentation de ZFS, les zpools sont l'équivalent des Volume Group (VG) dans LVM. Mais ce sont également eux qui s'occupent des niveaux de raid (c'est le cas du LVM d'AIX, mais pas de celui de linux). Ceci se gère dès la création du zpool.

Dans les exemples qui suivent, nous avons effacé les zpools précédemment créés et nous repartons avec 7 partitions de 5Go chacune : c0t2d0s0 à c0t2d0s6.


Création d'un pool simple

# zpool create zp_simple c0t2d0s0
# zpool list
NAME        SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_simple  4.97G  95.5K  4.97G     0%  ONLINE  -
# zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
zp_simple    72K  4.89G    21K  /zp_simple

Et voilà. Le résultat est instantané et "zfs list" nous indique qu'un FS a été créé et est déjà monté dans /zp_simple.

Supposons maintenant qu'on voulait le créer compressé et sans point de montage.

# zpool destroy zp_simple
# zpool create -m none -O compression=on zp_simple c0t2d0s0
# zpool list
NAME        SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_simple  4.97G   152K  4.97G     0%  ONLINE  -
# zfs list -o name,used,avail,refer,mountpoint,compress
NAME        USED  AVAIL  REFER  MOUNTPOINT  COMPRESS
zp_simple  82.5K  4.89G    21K  none              on

Et voilà, c'est aussi simple que ça. A noter que les options ne sont pas les mêmes qu'avec la commande zfs. Avec zpool, le point de montage se précise avec l'option "-m" (mise à none ici) et les options concernant les futurs FS se passent avec "-O" (lettre o majuscule). Je dis bien les futurs FS, car la compression sur un zpool n'a pas vraiment de sens, mais il faut savoir que les propriétés d'un FS sont, par défaut, héritées du FS père, ou du zpool père s'il n'y a pas de FS père. Donc dans ce dernier exemple, tous les FS créés dans zp_simple seront compressés et n'auront pas de point de montage. Mais si on spécifie un point de montage au prochain FS créé, alors ses descendants hériteront de son point de montage.

Une autre option qui peut être utile est "-f". Si le disque a déjà été utilisé en UFS, il est probable que zpool se rende compte qu'il a déjà servi et refuse de créer le pool, car il y a risque de conflit avec un FS existant, qui serait utilisé SVM (anciennement SDS). Si on est sûr que le disque est bien disponible, on va utiliser l'option "-f" qui va forcer la création du zpool.


Création d'un pool en raid0

# zpool create zp_raid0 c0t2d0s1 c0t2d0s2
# zpool list
NAME        SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid0   9.94G    97K  9.94G     0%  ONLINE  -
zp_simple  4.97G   166K  4.97G     0%  ONLINE  -
# zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
zp_raid0   73.5K  9.78G    21K  /zp_raid0
zp_simple    84K  4.89G    21K  none

Difficile de faire plus simple...

Nous allons en profiter pour voir une nouvelle commande : "zpool status" qui peut se taper seule ou avec une liste de zpools en argument. Exemple.

# zpool status zp_raid0
 pool: zp_raid0
 state: ONLINE
 scrub: none requested
config:

 NAME        STATE     READ WRITE CKSUM
 zp_raid0    ONLINE       0     0     0
 c0t2d0s1  ONLINE       0     0     0
 c0t2d0s2  ONLINE       0     0     0

 errors: No known data errors

Cette commande nous permet de voir l'état et la configuration du zpool. On peut voir précisément de quels vdevs (partitions) il est composé, et l'état de chacun des vdevs.


Création d'un pool en miroir (raid1)

On va rajouter le mot clé "mirror" pour préciser à zpool qu'il s'agit d'un mirroir.

# zpool create zp_raid1 mirror c0t2d0s3 c0t2d0s4
# zpool list
NAME        SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid0   9.94G    78K  9.94G     0%  ONLINE  -
zp_raid1   4.97G  95.5K  4.97G     0%  ONLINE  -
zp_simple  4.97G  88.5K  4.97G     0%  ONLINE  -

On voit bien que zp_raid1 ne fait que la moitié de la somme de ses deux vdevs.


Création d'un pool en raid 1+0

Il s'agit ici de créer deux miroirs qu'on va assembler. Commençons par supprimer les pools précédents.

# zpool destroy zp_simple ; zpool destroy zp_raid0 ; zpool destroy zp_raid1
# zpool create zp_raid10 mirror c0t2d0s0 c0t2d0s1 mirror c0t2d0s2 c0t2d0s3
# zpool list
NAME        SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid10  9.94G    97K  9.94G     0%  ONLINE  -
# zpool status
 pool: zp_raid10
 state: ONLINE
 scrub: none requested
config:

        NAME          STATE     READ WRITE CKSUM
        zp_raid10     ONLINE       0     0     0
          mirror-0    ONLINE       0     0     0
            c0t2d0s0  ONLINE       0     0     0
            c0t2d0s1  ONLINE       0     0     0
          mirror-1    ONLINE       0     0     0
            c0t2d0s2  ONLINE       0     0     0
            c0t2d0s3  ONLINE       0     0     0

errors: No known data errors

zpool status nous permet de bien voir que zp_raid10 est composé de deux mirroirs, chacun composé de deux vdevs. On peut ajouter autant de miroirs qu'on veut.


Création d'un zpool en raidz

En langage zfs, on ne parle pas de raid5 mais de raidz ou raidz1. En fait, le raidz est identique au raid5, à part que le calcul de la parité est différent. A la place du mot clé "mirror", on va mettre "raidz" ou "raidz1".

On va également introduire une nouvelle notion : celle de spare disk. Un spare disk est le disque qui va prendre le relais en cas de panne d'un des disques actifs. On ajoute le (ou les) spare disk(s) avec le mot clé "spare" suivit du ou des vdevs. Les spare disks fonctionnent également avec tous les niveaux de raid vu précédemment.

# zpool create zp_raid5 raidz c0t2d0s0 c0t2d0s1 c0t2d0s2 c0t2d0s3 spare c0t2d0s4
# zpool status
  pool: zp_raid5
 state: ONLINE
 scrub: none requested
config:

        NAME          STATE     READ WRITE CKSUM
        zp_raid5      ONLINE       0     0     0
          raidz1-0    ONLINE       0     0     0
            c0t2d0s0  ONLINE       0     0     0
            c0t2d0s1  ONLINE       0     0     0
            c0t2d0s2  ONLINE       0     0     0
            c0t2d0s3  ONLINE       0     0     0
        spares
          c0t2d0s4    AVAIL

errors: No known data error
# zpool list
NAME       SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid5  19.9G   147K  19.9G     0%  ONLINE  -

Pour les grandes quantités de disques, Oracle recommande l'utilisation de raidz2. Il s'agit d'un raid6, c'est à dire un raid5 avec double calcul de parité, pour pouvoir supporter la perte de deux disques. Les dernières versions de ZFS incluent également un niveau raidz3.


Import / export de zpools

Il peut être utile d'exporter et d'importer un zpool. Par exemple, dans le cas de deux serveurs reliés au même SAN, pour transférer le zpool sur l'autre serveur.

Pour exporter le zpool, on utilise "zpool export" et pour importer "zpool import". "zpool import" sert également à voir la liste des zpool possibles à importer ; utile pour vérifier que le zpool est bien visible du serveur.

# zpool list
NAME       SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid5  19.9G   147K  19.9G     0%  ONLINE  -
# zpool export zp_raid5
# zpool list
no pools available
# zpool import
  pool: zp_raid5
    id: 8634237456648565539
 state: ONLINE
action: The pool can be imported using its name or numeric identifier.
config:

        zp_raid5      ONLINE
          raidz1-0    ONLINE
            c0t2d0s0  ONLINE
            c0t2d0s1  ONLINE
            c0t2d0s2  ONLINE
            c0t2d0s3  ONLINE
        spares
          c0t2d0s4
# zpool list
no pools available
# zpool import zp_raid5
# zpool list
NAME       SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid5  19.9G   198K  19.9G     0%  ONLINE  -


Récupération de zpools détruits

Si on a supprimé par erreur un zpool avec "zpool destroy", tout espoir n'est pas perdu. Il faut utiliser "zpool import [-D]".

# zpool list
NAME       SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid5  19.9G   147K  19.9G     0%  ONLINE  -
# zpool destroy zp_raid5
# zpool list
no pools available
# zpool status zp_raid5
cannot open 'zp_raid5': no such pool
# zpool import
no pools available to import
# zpool import -D
 pool: zp_raid5
 id: 8634237456648565539
 state: ONLINE (DESTROYED)
action: The pool can be imported using its name or numeric identifier.
config:

        zp_raid5      ONLINE
          raidz1-0    ONLINE
            c0t2d0s0  ONLINE
            c0t2d0s1  ONLINE
            c0t2d0s2  ONLINE
            c0t2d0s3  ONLINE
        spares
            c0t2d0s4
# zpool import -D zp_raid5
# zpool list
NAME       SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid5  19.9G   198K  19.9G     0%  ONLINE  -

On remarque l'état "ONLINE (DESTROYED)" renvoyé par "zpool import -D".

Renommer un zpool

Il n'est pas possible de renommer un zpool actif. La solution est de l'exporter et de l'importer sous un nouveau nom. Par contre, le zpool est indisponible le temps de la manipulation. Même si ça ne dure que quelques secondes, c'est à réfléchir sur un serveur de production...

# zpool list
NAME       SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_raid5  19.9G   147K  19.9G     0%  ONLINE  -
# zpool export zp_raid5
# zpool import zp_raid5 zp_data
# zpool list
NAME      SIZE  ALLOC   FREE    CAP  HEALTH  ALTROOT
zp_data  19.9G   198K  19.9G     0%  ONLINE  -


Lister les disques d'un zpool

Il faut utiliser une commande que nous avons vu au début, lors de la création d'un zpool. La commande est "zpool status", qui peut se taper seule ou avec une liste de zpools en argument. Exemple.

# zpool status zp_raid0
 pool: zp_raid0
 state: ONLINE
 scrub: none requested
config:

 NAME        STATE     READ WRITE CKSUM
 zp_raid0    ONLINE       0     0     0
 c0t2d0s1  ONLINE       0     0     0
 c0t2d0s2  ONLINE       0     0     0

 errors: No known data errors

Compléments sur les FS

Nous avons vu toutes les fonctionnalités courantes dans le chapitre "Les bases de ZFS par l'exemple". Mais il y a encore quelques points intéressants à voir.


Montage et démontage

On monter et démonter des FS ZFS avec les commandes "zfs mount nom-du-FS" et "zfs umount nom-du-FS". Cette action est différente de "zfs set mountpoint=none". Cette dernière commande démonte le FS, mais supprime également le point de montage de la config ZFS et supprime le répertoire, alors que "zfs umount" ne fait que démonter le FS, mais conserve répertoire et config ZFS. Exemple.

# zfs list
NAME          USED  AVAIL  REFER  MOUNTPOINT
zp_data      10.1M  14.6G  10.0M  /zp_data
zp_data/foo  31.4K  2.00G  31.4K  /zp_data/foo
# df -h /zp_data/foo
Filesystem             size   used  avail capacity  Mounted on
zp_data/foo            2.0G    31K   2.0G     1%    /zp_data/foo
# zfs umount /zp_data/foo
# df -h /zp_data/foo
Filesystem             size   used  avail capacity  Mounted on
zp_data                 15G    10M    15G     1%    /zp_data
# zfs list
NAME          USED  AVAIL  REFER  MOUNTPOINT
zp_data      10.1M  14.6G  10.0M  /zp_data
zp_data/foo  31.4K  2.00G  31.4K  /zp_data/foo
# zfs set mountpoint=none zp_data/foo
# df -h /zp_data/foo
df: (/zp_data/foo) not a block device, directory or mounted resource
# zfs list
NAME          USED  AVAIL  REFER  MOUNTPOINT
zp_data      10.2M  14.6G  10.0M  /zp_data
zp_data/foo  31.4K  2.00G  31.4K  none


Partage NFS

On peut partager un FS avec ZFS dès sa création avec "zfs create -o sharenfs=ro ..." ou par la suite avec "zfs set sharenfs=ro ...". L'option peut être "=ro" pour un partage en lecture seule, ou "=on" pour un partage en lecture écriture.

On peut désactiver le partage (sans le supprimer) avec "zfs unshare nom-du-fs" et le réactiver avec "zfs share nom-du-fs". Au lieu du nom du FS, on peut mettre "-a" et ça va s'appliquer à tous les FS partagés avec ZFS.

On peut supprimer complètement le partage avec "zfs set sharenfs=off".

Voici un exemple.

# zfs list -o name,used,avail,refer,mountpoint,sharenfs
NAME          USED  AVAIL  REFER  MOUNTPOINT    SHARENFS
zp_data      10.2M  14.6G  10.0M  /zp_data      off
zp_data/foo  31.4K  2.00G  31.4K  /zp_data/foo  off
# share
# zfs set sharenfs=ro zp_data/foo
# zfs list -o name,used,avail,refer,mountpoint,sharenfs
NAME          USED  AVAIL  REFER  MOUNTPOINT    SHARENFS
zp_data      10.2M  14.6G  10.0M  /zp_data      off
zp_data/foo  31.4K  2.00G  31.4K  /zp_data/foo  ro
# share
-               /zp_data/foo   sec=sys,ro   ""
# zfs unshare zp_data/foo
# zfs list -o name,used,avail,refer,mountpoint,sharenfs
NAME          USED  AVAIL  REFER  MOUNTPOINT    SHARENFS
zp_data      10.2M  14.6G  10.0M  /zp_data      off
zp_data/foo  31.4K  2.00G  31.4K  /zp_data/foo  ro
# share
# zfs share zp_data/foo
# share
-               /zp_data/foo   sec=sys,ro   ""
# zfs set sharenfs=off zp_data/foo
# share
# zfs list -o name,used,avail,refer,mountpoint,sharenfs
NAME          USED  AVAIL  REFER  MOUNTPOINT    SHARENFS
zp_data      10.2M  14.6G  10.0M  /zp_data      off
zp_data/foo  31.4K  2.00G  31.4K  /zp_data/foo  off


Sous Solaris 11

La syntaxe a évolué sous Solaris 11. Il faut maintenant mettre les paramètres dans la valeur "share" et "sharenfs" n'accepte plus que "on" ou "off". Exemple :

zfs set share=name=mon_partage,path=/chemin,prot=nfs,rw=10.36.208.71 rpool/foo
zfs set sharenfs=on rpool/foo

Informations détaillées sur un FS

On peut obtenir tous les détails sur un FS particulier avec zfs get all comme dans l'exemple ci-dessous :

# zfs get all rpool/export/home
NAME               PROPERTY              VALUE                  SOURCE
rpool/export/home  aclinherit            restricted             default
rpool/export/home  aclmode               discard                default
rpool/export/home  atime                 on                     default
rpool/export/home  available             196G                   -
rpool/export/home  canmount              on                     default
rpool/export/home  casesensitivity       mixed                  -
rpool/export/home  checksum              on                     default
rpool/export/home  compression           off                    default
rpool/export/home  compressratio         1.00x                  -
rpool/export/home  copies                1                      default
rpool/export/home  creation              Wed Jun  5  7:59 2013  -
rpool/export/home  dedup                 off                    default
rpool/export/home  devices               on                     default
rpool/export/home  encryption            off                    -
rpool/export/home  exec                  on                     default
rpool/export/home  keychangedate         -                      default
rpool/export/home  keysource             none                   default
rpool/export/home  keystatus             none                   -
rpool/export/home  logbias               latency                default
rpool/export/home  mlslabel              none                   -
rpool/export/home  mounted               yes                    -
rpool/export/home  mountpoint            /export/home           inherited from rpool/export
rpool/export/home  multilevel            off                    -
rpool/export/home  nbmand                off                    default
rpool/export/home  normalization         none                   -
rpool/export/home  primarycache          all                    default
rpool/export/home  quota                 none                   default
rpool/export/home  readonly              off                    default
rpool/export/home  recordsize            128K                   default
rpool/export/home  referenced            34K                    -
rpool/export/home  refquota              none                   default
rpool/export/home  refreservation        none                   default
rpool/export/home  rekeydate             -                      default
rpool/export/home  reservation           none                   default
rpool/export/home  rstchown              on                     default
rpool/export/home  secondarycache        all                    default
rpool/export/home  setuid                on                     default
rpool/export/home  shadow                none                   -
rpool/export/home  share.*               ...                    inherited
rpool/export/home  snapdir               hidden                 default
rpool/export/home  sync                  standard               default
rpool/export/home  type                  filesystem             -
rpool/export/home  used                  2.19G                  -
rpool/export/home  usedbychildren        2.19G                  -
rpool/export/home  usedbydataset         34K                    -
rpool/export/home  usedbyrefreservation  0                      -
rpool/export/home  usedbysnapshots       0                      -
rpool/export/home  utf8only              off                    -
rpool/export/home  version               6                      -
rpool/export/home  vscan                 off                    default
rpool/export/home  xattr                 on                     default
rpool/export/home  zoned                 off                    default

Snapshots et clones

Les snapshots

Un snapshot (ou instantanné) est une copie en lecture seule d'un FS à un instant donné. Comme sous LVM, un snapshot ne prend aucune place au départ, mais grossi au fur et à mesure que les fichiers changent.

Création d'un snapshot

La commande est "zfs snapshot" suivie du nom du FS auquel on attache un "@" puis un nom quelconque. Il convient quand même de mettre un nom compréhensible par ses collègues...

# zfs snapshot [-r] pool/home@monday

Lister les snapshots

# zfs list -t snapshot

Détruire un snapshot

# zfs destroy [-r] pool/home@monday

Renommer un snapshot

# zfs rename pool/home@monday pool/home@2011-10-06
# zfs rename pool/home@monday @2011-10-06
# zfs rename pool/home@monday 2011-10-06
# zfs rename -r pool/home@monday 2011-10-06

Les exemples ci-dessus montrent que lorsqu'on renomme un snapshot, la partie de nom qui précède l'"@" est facultative, ainsi que l'"@" lui-même. C'est logique, puisque le snapshot est attaché à son FS et ne peut pas être déplacé ailleurs.

Revenir à l'état au moment du snapshot (annulation des modifs qui ont suivi la création du snapshot)

# zfs rollback pool/home@wednesday

Cette commande ne va fonctionner qu'avec le snapshot le plus récent (s'il y en a plusieurs). Si on veut revenir à un snapshot antérieur, il faut soit faire un rollback successif de tous les snapshots, soit forcer avec l'option "-r".


Les clones

Un clone est une copie en lecture/écriture d'un FS à un instant donné. Comme le snapshot, il ne consomme initialement aucun espace disque. On peut créer un snapshot d'un clone. Le clone se créé obligatoirement à partir d'un snapshot. Il peut se trouver dans une autre arborescence, mais obligatoirement dans le même zpool. Le snapshot ne pourra pas être détruit tant que le clone existera. Le clone n'hérite pas des propriétés du snapshot ni du FS d'origine (quota, etc...).

Un clone n'est donc pas un copier/coller d'un FS. Pour ce faire, il faut utiliser zfs send et zfs recv (voir juste après).


Créer un clone

# zfs snapshot pool/home/toto@thursday
# zfs clone pool/home/toto@thursday pool/test/bug123

Détruire un clone

# zfs destroy pool/test/bug123

Remplacer un FS par un clone de ce même FS.

# zfs create pool/test
# zfs create pool/test/foo
# zfs snapshot pool/test/foo@tuesday
# zfs clone pool/test/foo@tuesday pool/test/fooClone
# zfs list -r pool/test
#   ==> USED à 0 sur snapshot et clone, mais à vraie valeur sur pool/test/foo
# zfs promote pool/test/fooClone
# zfs list -r pool/test
#   ==> USED passe à 0 sur pool/test/foo et à vraie valeur sur pool/test/fooClone

Pour faire plus propre, on renome

# zfs rename pool/test/foo pool/test/fooOld
# zfs rename pool/test/fooClone pool/test/foo

Et éventuellement

# zfs destroy pool/test/fooOld

Envoi et réception de données ZFS

On utilise les commandes zfs send et zfs recv pour envoyer et recevoir une copie d'un flux de snapshot.

On peut envoyer le flux vers un autre pool et même vers un autre pool d'un autre serveur.

# zfs send pool/data@today | zfs recv pool2/foo
# zfs send pool/data@today | ssh rhost zfs recv pool2/foo

Le cas que nous venons de voir est l'envoi/réception d'un flux complet. Le FS de destination ne doit pas exister (il est automatiquement créé). Mais on peut envoyer un flux incrémentiel avec l'option "-i".

# zfs send -i pool/data@yesterday pool/data@today | ssh rhost zfs recv pool2/foo

Dans ce cas, le zpool pool2 doit préalablement exister.

La commande suivante fait exactement la même chose :

# zfs send -i yesterday pool/data@tody > ssh rhost zfs recv pool2/foo

On peut également envoyer le flux de sortie dans un fichier.

# zfs send pool/data@yesterday | gzip > backup_zfs.gz

Exemple d'utilisation avec des fichiers.

# zfs send pool/data@today > /backup/data.bkp
# zfs recv pool2/foo < /backup/data.bkp

Autres options :

  • -I : envoie tous les flux incrémentiels d'un snapshot à un snapshot cummulé. Permet de créer un clone. Le FS de destination doit préalablement exister.
  • -i n'envoie que le snapshot le plus récent, -I envoie tous les snapshots créés entre les deux snapshots mis en arguments (voir exemple plus bas).
  • -R : envoie le flux de réplication de tous les FS descendants. Les propriétés, snapshots, FS descendants et clones sont conservés
# zfs send -I pool/fs@snap1 pool/fs@snap4 > /backup/fs@all-I   # => envoie tous les snapshots de snap1 à snap4
# zfs receive -d -F pool/fs < /backup/fs@all-I                 # => zfs list affichera bien snap1, snap2, snap3 et snap4

L'option -I permet également d'envoyer à la fois des snapshots et des clones.

Exemple de recopie complète d'une arborescence zfs dans un autre pool :

# zfs snapshot -r users@today
# zfs send -R users@today > /backup/users-R
# zfs create users2 mirror c0t1d1 c1t1d1
# zfs receive -F -d users2 < /backup/users-R

Un zfs list affichera un contenu identique (snapshots, clones, arborescence,...) pour les pools users et users2.


Mirrorer le disque système

Pour voir comment fonctionne le mirroring du système, on va suivre un exemple. Dans cet exemple, le disque système de départ est c1t0d0 et celui qui va être son miroir est c1t1d0.

  • Installer le système en ZFS sur c1t0d0 ; le pool garde le nom par défaut "rpool".
  • Vérifier le statut du pool
# zpool status
 pool: rpool
 state: ONLINE
 scrub: none requested
config:

 NAME        STATE     READ WRITE CKSUM
 rpool       ONLINE       0     0     0
 c1t0d0s0  ONLINE       0     0     0

errors: No known data errors
  • copier le partitionnement du disque principal vers le miroir (le miroir doit être au moins aussi grand que le disque principal)
# prtvtoc /dev/rdsk/c1t0d0s2 | fmthard -s - /dev/rdsk/c1t1d0s2
  • on attache le nouveau disque au premier, ce qui implique qu'il va être mis en miroir (si on ajoute "add" au lieu d'attacher "attach", on créé des volumes concaténés et pas mirrorés), puis on vérifie le nouvel état du pool
# zpool attach -f rpool c1t0d0s0 c1t1d0s0
Please be sure to invoke installboot(1M) to make 'c1t1d0s0' bootable.
Make sure to wait until resilver is done before rebooting.

# zpool status rpool
 pool: rpool
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
 continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress for 0h0m, 28.90% done, 0h0m to go
config:

 NAME          STATE     READ WRITE CKSUM
 rpool         ONLINE       0     0     0
 mirror-0    ONLINE       0     0     0
 c1t0d0s0  ONLINE       0     0     0
 c1t1d0s0  ONLINE       0     0     0  1.65G resilvered

errors: No known data errors

Attention, sur l'exemple ci-dessus, on voit que la synchronisation des disques est en cours (28.90%, sur la ligne qui commence par "scrub:"). Il faut bien attendre qu'elle soit terminée avant de passer à la suite. Quand c'est terminé, la ligne "scrub:" ressemble à ceci :

scrub: resilver completed after 0h4m with 0 errors on Thu Feb  3 16:42:44 2011

  • rendre le disque bootable en appliquant les blocs d'initialisation au disque miroir
# installboot -F zfs /usr/platform/`uname -i`/lib/fs/zfs/bootblk /dev/rdsk/c1t1d0s0
  • modifier l'OBP pour que les deux disques soient vus comme disques de boot

soit depuis l'OBP (conseillé)

ok nvalias zfsdisk /pci@0/pci@0/pci@2/scsi@0/disk@0,0:a
ok nvalias zfsmirror /pci@0/pci@0/pci@2/scsi@0/disk@1,0:a
ok setenv boot-device zfsdisk zfsmirror
ok setenv use-nvramrc? true
ok reset-all

soit depuis le serveur (moins conseillé, car parfois les lignes trop longues passent mal)

# eeprom "nvramrc=devalias zfsdsk /pci@0/pci@0/pci@2/scsi@0/disk@0,0:a zfsmirror /pci@0/pci@0/pci@2/scsi@0/disk@1,0:a"
# eeprom "boot-device= zfsdisk zfsmirror"
# eeprom "use-nvramrc?=true"
  • on peut verifier que ça fonctionne en retirant un disque et en rebootant sur l'autre. Puis idem avec l'autre disque.

Lorsqu'on retire un des disques, le zpool status rpool renvoie un résultat du genre

# zpool status rpool
 pool: rpool
 state: DEGRADED
status: One or more devices has been removed by the administrator.
 Sufficient replicas exist for the pool to continue functioning in a
 degraded state.
action: Online the device using 'zpool online' or replace the device with
 'zpool replace'.
 scrub: none requested
config:

 NAME          STATE     READ WRITE CKSUM
 rpool         DEGRADED     0     0     0
 mirror-0    DEGRADED     0     0     0
 c1t0d0s0  REMOVED      0     0     0
 c1t1d0s0  ONLINE       0     0     0

errors: No known data errors

Normalement, lorsqu'on remet le disque, il se réactive tout seul. Sinon on peut le réactiver manuellement :

# zpool online c1t0d0s0

Le swap sous ZFS

Il est possible de faire une partition dédiée au swap sous ZFS, mais on ne peut pas créer un FS comme nous l'avons vu jusque là. Il faut créer ce qui s'appelle un volume ZFS. C'est quasiment pareil, sauf que la taille est fixe, et non redimensionnable. Il faut également préciser la taille du block, qui va être différente entre Sparc et x86. Exemples de création d'un volume de 30Go :

  • sur Sparc :
# zfs create -V 30G -b 8k zp_data/swap
  • sur x86 :
# zfs create -V 30G -b 4k zp_data/swap

Ceci va créer un volume qui sera accessible depuis /dev/zvol/dsk/zp_data/swap. C'est ce chemin qu'on va utiliser la vfstab et pour l'ajout à chaud :

# swap -a /dev/zvol/dsk/zp_data/swap
# swap -l
swapfile             dev  swaplo blocks   free
/dev/zvol/dsk/zp_data/swap 256,1      16 62914544 62914544

Et voilà, notre volume de swap est activé et pris en compte.


Attention : il est fortement déconseillé par Oracle de mélanger des volumes swap "classiques" SVM et ZFS. Dans la pratique, il m'est arrivé de voir planter sans raison apparente un serveur configuré avec de la swap ZFS et SVM mélangés, et plus aucun plantage après n'avoir laissé que la swap ZFS (et aucun plantage non plus quand il n'y avait que de la swap "classique" SVM).


Les datasets

Les datasets permettent de déléguer la gestion des zfs à une zone. Dans la pratique, on créé un ZFS, sans point de montage, on le rajoute via zonecfg, et on redémarre la zone pour prise en compte. Ensuite, toutes les commandes zfs se font depuis la zone.

Je ne vais pas revenir sur la création d'un ZFS. Voici la syntaxe pour ajouter un dataset à une zone :

# zonecfg -z ma_zone
zonecfg:ma_zone> add dataset
zonecfg:ma_zone:dataset> set name=zp_mazone/apps
zonecfg:ma_zone:dataset> end

Le dataset peut également être un zpool.

Après reboot de la zone, on peut créer les zfs depuis la zone, à partir de ce zfs "père". Avec les versions récentes de Solaris 11 (depuis la 11.2 il me semble), il n'est plus nécessaire de rebooter la zone pour prise en compte des datasets. Maintenant on peut "forcer" l'application de la configuration de la zone, avec la commande :

# zoneadm -z ma_zone apply

Tunning

Cache (zfs_arc_max)

Par défaut, ZFS s'octroie la totalité du swap, moins 1Go, comme mémoire cache. Si des applications en ont besoin, il la libère au fur et à mesure. Ça peut poser problème, car il peut mettre un peu de temps à rendre la mémoire, et ça peut être perturbant car on voit que le swap est utilisé quasiment à fond, alors que si on totalise la consommation des applications, on n’atteint pas la valeur réellement consommée. Il existe donc un moyen de limiter cette consommation excessive de swap, avec la variable zfs_arc_max dans /etc/system. Exemple de limitation, ligne à ajouter dans /etc/system :

* Limit ZFS ARC cache to 4GB
set zfs:zfs_arc_max=4294967296

Il faut rebooter pour que ce soit pris en compte.

Pour voir la valeur actuellement attribuée :

$ kstat zfs:0:arcstats:size
module: zfs                             instance: 0     
name:   arcstats                        class:    misc
	size                            43336599728

$ echo $((43336599728/1024/1024/1024))
40

Ici on est à 40Go.

Contraintes et préconisations d'Oracle

  • le nom d'un zpool ou d'un FS ne peut contenir que des caractères alphanumériques ainsi que des "-", "_", ":" ou "."
  • la création de FS étant très peu coûteuse en temps et ressources, Oracle recommande de créer un FS par utilisateur, projet, etc. Ceci permet également de contrôler facilement les quotas, réservations et sauvegardes par utilisateur ou projet.
  • Oracle recommande d'utiliser ZFS à partir de l'update 2 de Solaris (6/06)
  • attention aux ACLs qui ne se gèrent plus de la même façon qu'un UFS. Elles sont plus complètes avec ZFS.