Le fonctionnement des snapshots

Si les tractations entre Apple et Sun s’étaient passées correctement, les utilisateurs de Mac OS X auraient pu profiter d’ici un an ou deux d’un fabuleux système de fichiers : ZFS. Mais comme souvent, l’intérêt des clients passe après les intérêts de l’entreprise, et il semble finalement qu’Apple ait décidé de créer son propre nouveau système de fichiers.

Un aspect sympathique de ZFS (parmi tant d’autres !), est sa capacité à générer et gérer des snapshots. Un snapshot, c’est une sorte de photographie à un instant donné d’un système de fichiers. Cette photographie peut alors être montée comme n’importe quel autre système de fichiers, elle peut servir de base à une sauvegarde, elle peut servir à rechercher un fichier effacé après la création du snapshot…
Plus que l’utilité évidente en matière de sauvegarde de ces snapshots, j’aimerai revenir sur leur fonctionnement interne, car c’est là que réside toute la magie. En effet, au premier abord l’idée d’une photographie à un instant T de son disque dur semble séduisante, mais très rapidement des voix s’élèvent qui s’interrogent sur le temps que cela prend, la place que cela occupe… Imaginez votre disque dur de 250 Go, 500 Go, ou même 1 To, bien rempli. Vous concluez naturellement que pour faire un snapshot de votre volume, il vous faudra un disque dur externe, de grande capacité, et que cela prend un temps fou. Fort heureusement, c’est faux.

ZFS crée ses snapshots selon le mode copy on write, tout comme le système de fichiers par défaut de FreeBSD : UFS. C’est ce dernier que je vais utiliser pour présenter le fonctionnement des snapshots. Il est probable que l’implémentation des snapshots dans ZFS diffère légèrement, mais la logique reste la même, et de nombreux autres systèmes la partage.

Attention. Les explications suivantes sont parfois simplifiées outrageusement. D'une part car les informations techniques précises sont très dispersées et pas toujours très claires ni faciles à se procurer. D'autre part pour rendre compte de manière accessible des mécanismes généraux impliqués dans la création de snapshots.
Si vous êtes un as des systèmes de fichiers et des snapshot, n'hésitez pas à proposer des rectifications.

Sur un système de fichiers, les données sont organisées en blocs. Au début du système de fichiers, un index des blocs existe qui permet de retrouver les différents blocs appartenant à chaque fichier. On parle de block bitmaps. À l’instant T où je crée un snapshot d’un système de fichiers, je n’ai pas besoin de recopier l’intégralité du disque, car tous les fichiers s’y trouvent déjà. J’ai juste besoin de faire une image des block bitmaps.
Si on recopiait les block bitmaps à l’identique, on ne pourrait pas monter un snapshot comme on le fait avec une image disque classique. En effet, les block bitmaps du snapshot pointeraient vers des blocs que l’on n’a pas recopiés, sans que le système puisse le savoir. En réalité, à la création du snapshot, toutes les références contenues dans les block bitmaps sont traduites. Quand l’index d’origine référence un bloc vide, alors l’index du snapshot utilise le pointeur not used, et si l’index d’origine référence un bloc utilisé, alors l’index du snapshot utilise le pointeur not copied.
Finalement, juste au moment de sa création, le snapshot ne contient que des indexes remplis de pointeurs not used et not copied. Cela prend très peu de place, et la création est relativement rapide (instantanée sur ZFS, parfois longue sur UFS).

L’utilisateur se dit maintenant que si il modifie ou efface un fichier, son snapshot ne lui servira à rien puisque tous les blocs de données résident sur le système de fichiers et non pas sur le snapshot. C’est ici qu’intervient le mécanisme de copy on write. L’instant T est passé, le snapshot existe, système et utilisateurs écrivent sur le disque. Le système sait qu’un snapshot existe, il intercepte donc toute les demandes d’écriture, et les converti en “copie à l’écriture”.

Voici ce qui se passe lors de l’effacement d’un bloc sur le système de fichier (suppression ou réécriture d’un fichier, par exemple) :

  1. Le système intercepte la demande d’écriture.
  2. Il lit le pointeur correspondant dans l’index du snapshot.
  3. Si le pointeur est à not copied, le système recopie le bloc dans le snapshot, et met à jour l’index du snapshot pour qu’il pointe vers ce nouveau bloc, et non plus vers not copied.
  4. Si le pointeur est à not used ou si il contient déjà l’adresse d’un bloc du snapshot, rien n’est modifié dans le snapshot.
  5. Enfin, le bloc est effacé sur le système de fichiers.

Pour ceux qui ont besoin d'un dessin, voici un schéma trop compliqué (et donc forcément faux) du mécanisme de copy on write appliqué au snapshot. En haut, l'étape T=0 : le snapshot est créé. Au milieu, la réécriture des blocs (suppression du fichier bleu marine) est interceptée : les blocs sont recopiés dans le snapshot, la block bitmap du snapshot est mise à jour. En bas, l'écriture est faite sur le système de fichier original : le fichier n'existe plus, les indexes correspondant sont vidés.

copy-on-write

L’ajout de fichiers sur le système de fichiers ne fait pas grossir le snapshot, car ce dernier doit continuer de référencer les blocs not used correspondants, pour maintenir une image fidèle du système de fichiers à l’instant T. De même, les réécritures multiples de blocs n’ont pas d’impact sur la taille du snapshot, car ce dernier ne conserve qu’une version des blocs : celle qui date de l’instant T.

On peut donc dire que la taille d’un snapshot est approximativement égale à la taille des blocs utilisés à sa création et qui ont été modifiés depuis. Mais il faut surtout retenir que la taille d’un snapshot dépend beaucoup de l’utilisation que l’on fait de son système de fichiers, et de la durée de vie de ce snapshot. En effet, tant qu’il n’a pas été supprimé, un snapshot est toujours maintenu par le système. Sa taille maximum théorique est égale au volume de données stocké sur le système de fichier de départ.
On peut lire en divers endroits que la taille d’un snapshot est en général 10 à 15% de la taille du système de fichiers original. C’est une estimation tout à fait farfelue qui ne repose sur rien de concret. Seule l’expérience ou une analyse très fine de vos usages permet d’estimer la taille que vos snapshots pourraient atteindre. Par exemple, nous avons calculé que la taille d’un snapshot quotidien de la baie RAID qui stocke les emails de l’Université Lyon 2 occuperait moins de 1% du volume occupé par les messages eux-même (par jour d’existence).

Quand l’utilisateur lit le snapshot, le système lui présente une vue cohérente de son système de fichiers à l’instant T. Le système lit les block bitmaps du snapshot, et reconstitue les fichiers. Quand il tombe sur un pointeur not copied, il sait que le bloc n’a pas été modifié depuis la création du snapshot, et qu’il peut retrouver ce bloc sur le système de fichiers d’origine. Quand il tombe sur un pointeur qui désigne une adresse de bloc dans le snapshot il sait que le bloc a été modifié entre temps, et que son contenu à l’instant T est stocké dans le snapshot.
À cause de cette dépendance entre les block bitmaps et les blocs de données, un snapshot doit forcément résider sur le système de fichiers qu’il réplique. Il est donc malheureusement impossible d’avoir un snapshot d’un disque sur un second disque.

Un peu de lecture pour aller plus loin :
ZFS et snapshot

UFS et snapshot

Related posts

Laisser un commentaire

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

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.