Aller au contenu principal

Btrfs, meilleures sauvegardes ?

Dans un précédent article, je vous ai présenté le système de fichiers Btrfs, et comment SysNux l'utilise. Néanmoins je n'ai pas présenté la possibilité de créer des snapshots, et de les utiliser dans le cadre d'une politique de sauvegardes : c'est l'objet de ce nouvel article.

Snapshot ?

Le terme de snapshot indique la possibilité de figer l'état du système de fichiers à un instant donné.

De par son fonctionnement interne, Btrfs peut littéralement dupliquer le système de fichiers en une fraction de secondes, sans consommer de place supplémentaire sur le disque ! En réalité, il ne fait que dupliquer les références vers les données. Tant que les fichiers figés ne sont pas modifiés, ils ne consomment pas de place supplémentaire sur le disque, Btrfs conservera simplement deux liens vers ces fichiers. Lorsqu'un fichier est modifié par l'utilisateur, il faut vous rappeler que Btrfs effectue une copie sur écriture (COW) : la modification est écrite ailleurs sur le système de fichiers, l'original n'est pas modifié sur place. Si le fichier appartient à un snapshot, Btrfs ne libère simplement pas l'ancien espace, et on peut, si nécessaire, récupérer le fichier original à tout moment. Après modification, de l'espace est naturellement consommé sur le disque par le snapshot.

Pour Btrfs, un instantané est un sous-volume spécial, il faut donc utiliser la commande btrfs subvolume snapshot …

Par exemple, pour créer un snapshot du répertoire "Photos", dans le dossier "jdg/tmp/Photos" :

[jdg@tiare home]$ time sudo btrfs subvolume snapshot Photos/ jdg/tmp/Photos
Create a snapshot of 'Photos/' in 'jdg/tmp/Photos'

real    0m0.340s
user    0m0.007s
sys     0m0.039s

Après avoir préciser que le répertoire "Photos" occupe plus de 300 Go, on apprécie encore mieux le temps d'exécution de 0,3 s !

En ajoutant l'option -r à la commande précédente, on réalise un instantané accessible uniquement en lecture : on peut le considérer comme un premier pas vers une sauvegarde très aisée, mais il ne faut pas oublier que les données ne sont pas écrites sur un autre disque. En cas de problème matériel sur le disque, les données sont irrémédiablement perdues !

Voyage dans le temps

Comme les snapshots sont presque gratuits en terme d'occupation disque ou CPU, il devient possible d'en prendre très régulièrement afin de se prémunir contre les malveillances, les erreurs logicielles ou… humaines ! Certains n'hésitent pas à prendre des instantanés toutes les dix minutes, pour pouvoir récupérer les fichiers en cas d'effacement accidentel ; la distribution Linux Suse effectue un instantané avant mise à jour du système, ce qui permet de revenir en arrière en cas de problème. On comprend aussi l'intérêt en cas de contamination par un ransomware, ces logiciels qui chiffrent les données et exigent le paiement d'une rançon pour déchiffrer.

SysNux a choisi d'effectuer (via un script appelé par cron) des instantanés des principaux volumes toutes les heures (de 7 heures à 19 heures), puis quotidiennement, et mensuellement. Les 14 derniers instantanés horaires sont conservés, ainsi que les 7 derniers quotidiens, et les 4 derniers hebdomadaires. Les instantanés sont nommés en fonction de la date et l'heure, par exemple on obtient pour le volume "SysNux" :

[jdg@tiare ~]$ ls -d /mnt/snapshots/SysNux_*ly*
/mnt/snapshots/SysNux_daily_20160605-230004
/mnt/snapshots/SysNux_daily_20160606-230005
/mnt/snapshots/SysNux_daily_20160607-230004
/mnt/snapshots/SysNux_daily_20160608-230004
/mnt/snapshots/SysNux_daily_20160609-230005
/mnt/snapshots/SysNux_daily_20160610-230004
/mnt/snapshots/SysNux_daily_20160611-230004
/mnt/snapshots/SysNux_hourly_20160611-180004
/mnt/snapshots/SysNux_hourly_20160611-190004
/mnt/snapshots/SysNux_hourly_20160612-070005
/mnt/snapshots/SysNux_hourly_20160612-080004
/mnt/snapshots/SysNux_hourly_20160612-090004
/mnt/snapshots/SysNux_hourly_20160612-100004
/mnt/snapshots/SysNux_hourly_20160612-110004
/mnt/snapshots/SysNux_hourly_20160612-120004
/mnt/snapshots/SysNux_hourly_20160612-130003
/mnt/snapshots/SysNux_hourly_20160612-140004
/mnt/snapshots/SysNux_hourly_20160612-150003
/mnt/snapshots/SysNux_hourly_20160612-160004
/mnt/snapshots/SysNux_hourly_20160612-170005
/mnt/snapshots/SysNux_hourly_20160612-180004
/mnt/snapshots/SysNux_weekly_20160515-233004
/mnt/snapshots/SysNux_weekly_20160522-233004
/mnt/snapshots/SysNux_weekly_20160529-233005
/mnt/snapshots/SysNux_weekly_20160605-233004

Ainsi, je peux retrouver l'état d'un fichier quelconque (document, image, son, vidéo) tel qu'il était trois heures, un jour ou deux semaines auparavant. Par exemple, pour le fichier "journal.odt" :

[jdg@tiare snapshots]$ ls -l ~/journal.odt jdg_hourly_20160612-150002/journal.odt jdg_daily_20160611-230002/journal.odt jdg_weekly_20160529-233002/journal.odt 
-rw-rw-r--. 1 jdg jdg 462818  6 juin  11:40 /home/jdg/journal.odt
-rw-rw-r--. 1 jdg jdg 462818  6 juin  11:40 jdg_daily_20160611-230002/journal.odt
-rw-rw-r--. 1 jdg jdg 462818  6 juin  11:40 jdg_hourly_20160612-150002/journal.odt
-rw-rw-r--. 1 jdg jdg 460407 23 mai   17:16 jdg_weekly_20160529-233002/journal.odt

On obtient ainsi une véritable machine à remonter le temps !

Sauvegardes

Comme indiqué précédemment, les snapshots ne constituent pas des sauvegardes, car ils doivent résider sur le même système de fichiers, donc le même disque. En cas de panne du disque, tout est perdu.

Un développeur a eu la bonne idée d'implémenter la possibilité d'envoyer les données d'un snapshot vers la sortie standard, ou un fichier, via la commande btrfs send nom_snapshot.

Naturellement, le même développeur a aussi créé la commande inverse, btrfs receive point_de_montage, qui permet de recevoir le flux et créer le volume correspondant au point de montage.

En combinant les deux commandes, on obtient finalement une véritable sauvegarde, puisqu'on va pouvoir dupliquer un snapshot sur un autre système de fichiers, donc éventuellement un autre disque :

btrfs send /snaps/vol | btrfs receive -v /mnt/backup

À noter que, comme la commande d'envoi crée un flux de données, il peut être envoyé vers une autre machine, tout simplement avec la commande ssh. Par exemple, la commande ci-dessous permet de récupérer sur la machine "asterisk" le snapshot "/.snapshot-20130325", et de le stocker dans un fichier de la machine "tiare" :

[jdg@tiare ~]$ ssh asterisk sudo btrfs send /.snapshot-20160325 > asterisk.sysnux.pf-20160325.btrfs_send_stream

La commande d'envoi peut aussi calculer de manière très efficace la différence entre deux snapshots (option -p). Dans le cadre des sauvegardes, c'est évidemment très utile, puisque cela permet d'effectuer des sauvegardes différentielles plutôt que totales pour réduire l'espace nécessaire. Le principe est d'initialiser la sauvegarde par un premier snapshot, de l'envoyer vers un autre disque (ou une autre machine) ; puis lors de la sauvegarde suivante, l'utiliser comme base pour une sauvegarde incrémentielle. La rétention sur le disque de sauvegarde met à nouveau à profit le système de snapshots, dont l'efficacité permet de conserver un historique important.

Les sauvegardes de SysNux fonctionnent sur ce principe depuis quelques mois.

btrfs-snapshots-diff

Un petit script Python a été écrit, qui affiche les différences entre deux instantanés, en utilisant btrfs send pour la calculer de manière très efficace. Voir le projet sur GitHub pour plus d'informations.

Bug ?

Lors de la mise en place de ce système de sauvegardes, des erreurs d'allocation mémoire apparaissaient parfois au niveau du noyau Linux, par exemple :

[ 3734.651439] btrfs: page allocation failure: order:4, mode:0x2404040
[ 3734.651447] CPU: 2 PID: 7577 Comm: btrfs Not tainted
4.4.6-300.fc23.x86_64 #1
[ 3734.651449] Hardware name:                  /DZ68DB, BIOS
DBZ6810H.86A.0014.2011.0413.1049 04/13/2011
[ 3734.651452]  0000000000000286 0000000063f642d6 ffff8801000938a8
ffffffff813b542e
[ 3734.651456]  0000000002404040 0000000000000000 ffff880100093938
ffffffff811b2f8a
[ 3734.651460]  0000000100000040 00000000000938d0 0000000063f642d6
0000000000000004
[ 3734.651463] Call Trace:
[ 3734.651473]  [<ffffffff813b542e>] dump_stack+0x63/0x85
[ 3734.651477]  [<ffffffff811b2f8a>] warn_alloc_failed+0xfa/0x160
...

J'ai rapporté l'erreur sur la liste Btrfs le 29 mars… et une explication et un correction étaient fournies dès le lendemain !

La correction écrite par David Sterba, l'un des développeurs Btrfs a été intégrée à la version 4.5.5 du noyau Linux :

From: David Sterba 

commit 8f282f71eaee7ac979cdbe525f76daa0722798a8 upstream.

The allocation of node could fail if the memory is too fragmented for a
given node size, practically observed with 64k.

Reported-and-tested-by: Jean-Denis Girard 
Signed-off-by: David Sterba 
Signed-off-by: Greg Kroah-Hartman 

Conclusion

Le système de snapshots est encore une autre fonctionnalité très intéressante du système de fichier Btrfs. L'article a montré comment la mettre à profit, à travers la machine à remonter le temps, ou les meilleures sauvegardes.

La question de la place occupée par les snapshots n'a pas été abordée : elle passe par l'utilisation de quotas, qui pose malheureusement des problèmes actuellement. L'occasion d'un nouvel article lorsque les problèmes auront été réglés ?