ZFS
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 ). 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...
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.