🗂 Tirer parti de la déduplication de BTRFS: cas concret du versionnage
Le problème
Il m’est arrivé à plusieurs reprises de travailler sur des projets utilisant la librairie python filedepot, cette librairie est bien pratique pour gérer le stockage de fichier notamment en combinaison avec Sqlalchemy.
Un point qui ne reste néanmoins pas forcément évident à gérer par-dessus ce type de librairie est la question du versionnage. Un cas que j’ai eu l’occasion de voir est le versionnage dans Tracim ou un contenu à diverse révision qui peuvent ou non avoir un contenu fichier associé différent.
Le fonctionnement du champ UploadedFileField
proposé pour Sqlalchemy
par filedepot
, fonctionne de sorte à considérer
que le fichier est liée uniquement à une ligne de base de donnée et il peut être compliqué de tenter de partage un identifiant d’un même fichier entre divers
contenus, car par exemple, la suppression d’une ligne avec le contenu 1 supprimera le fichier associé, 2 pointant
vers le même contenu ne pourra plus y accéder.
Comment alors éviter que pour une modification mineure non liée au fichier, que le fichier soit dupliqué inutilement consommant ainsi de l’espace inutilement ?
Je vois alors plusieurs approches :
- Mettre cette intelligence de « versionnage » dans
filedepot
, mais cela demanderait un gros travail. - Mettre cette intelligence de « versionnage » dans l’application qui utilise filedepot notamment une table association entre l’identifiant du fichier pour l’application et le champ. Ce qui réduirait un peu l’intérêt simplificateur de filedepot à mon sens.
- Créer une sorte de couche intermédiaire d’intelligence entre filedepot qui gère cela. Cela pourrait être aussi l’occasion de gérer d’autres features lié au traitement du fichier : indexation, génération de preview, …
Si la troisième solution me semble la plus intéressante a creusé, elle demande du temps à mettre en place.
Ayant envie de gagner un peu d’espace disponible sur mon serveur utilisant Tracim
,
j’ai trouvé une solution de contournement à partir du fait que btrfs supporte la fonctionnalité de déduplication.
La Déduplication Quézako ?
La déduplication est une fonctionnalité de système de fichier qui permet à un système de fichier de dire qu’un certain
contenu utilisé par plusieurs fichiers est au même endroit. Ainsi, il est possible de copier via cp --reflink=always
sans utiliser d’espace supplémentaire (sauf quelques meta-données).
Seul certain système de fichier supporte cette fonctionnalité dont BTRFS.
À noter que cette fonctionnalité est activé par default dans cp quand c’est possible à partir de coreutils-9.0.
Ainsi, si vous utilisez un simple cp
dans un Gnu/Linux assez récent et utilisé un système de fichier comme btrfs, votre copie
sera gérer automatiquement intelligemment sans réelle copie.
Revenons à nos moutons
Mais du coup, qu’est-ce que ça change pour nous ? Parce qu’on pourrait effectivement ajuster
filedepot
pour faire de la copie viareflink
, mais il faudrait pour cela… Qu’il soit conscient qu’il réalise une copie. Et donc on retombe dans une problématique de développement plus ou moins complexe…
Oui … Sauf qu’il y a une astuce !
Il est possible de réaliser la déduplication a posteriori, quand on considère que c’est nécessaire grâce à un outil
comme Duperemove
. Ainsi, il m’est possible de récupérer de l’espace disque sans avoir à me soucier de l’optimalité ou
non des solutions techniques de stockage utilisé par le logiciel utilisé.
L’autre grosse force est que cela fonctionne pour tous les fichiers sans la moindre distinction. Ainsi peu importe si la duplication est le fait d’un utilisateur qui aurait copié 2 fois le même fichier, d’un mécanisme de versionnage non intelligent, ou simplement le hasard de 2 utilisateurs qui ne se connaissent même pas qui téléverse l’exacte, même contenu, la déduplication s’effectuera.
Voici un exemple, Avec un tracim 4.5 tout neuf en conteneur et son contenu dans un système btrfs tout propre dans un fichier (grâce à ce commentaire) :
Ajout d’un 1 fichier un peu gros sur l’instance :
df -h .
Filesystem Size Used Avail Use% Mounted on
/dev/loop0 10G 219M 9,3G 3% /mnt/dsk
Création de 2 nouvelles révisions sans vraie modification du fichier :
Filesystem Size Used Avail Use% Mounted on
/dev/loop0 10G 639M 8,9G 7% /mnt/dsk
Let’s go la déduplication (en utilisant l’exemple de https://wiki.tnonline.net/w/Btrfs/Deduplication/Duperemove):
root@gnu:/mnt/dsk# chrt -i 0 duperemove -A -h -d -r -v -b128k --dedupe-options=noblock,same --lookup-extents=yes --io-threads=1 var/data/depot
Using 128K blocks
Using hash: murmur3
Gathering file list...
Skipping small file /mnt/dsk/var/data/depot/2031c9c0-076e-11ee-9c12-0242ac110002/file
Skipping small file /mnt/dsk/var/data/depot/2031c9c0-076e-11ee-9c12-0242ac110002/metadata.json
Skipping small file /mnt/dsk/var/data/depot/2032025a-076e-11ee-9c12-0242ac110002/file
Skipping small file /mnt/dsk/var/data/depot/2032025a-076e-11ee-9c12-0242ac110002/metadata.json
Skipping small file /mnt/dsk/var/data/depot/cb00f218-076e-11ee-a461-0242ac110002/file
Skipping small file /mnt/dsk/var/data/depot/cb00f218-076e-11ee-a461-0242ac110002/metadata.json
Skipping small file /mnt/dsk/var/data/depot/cb0142b8-076e-11ee-a461-0242ac110002/file
Skipping small file /mnt/dsk/var/data/depot/cb0142b8-076e-11ee-a461-0242ac110002/metadata.json
Skipping small file /mnt/dsk/var/data/depot/e89f0f58-076e-11ee-827e-0242ac110002/metadata.json
Skipping small file /mnt/dsk/var/data/depot/0f1a60a6-076f-11ee-a200-0242ac110002/metadata.json
Skipping small file /mnt/dsk/var/data/depot/55639ca8-076f-11ee-a315-0242ac110002/metadata.json
Using 1 threads for file hashing phase
[1/3] (33.33%) csum: /mnt/dsk/var/data/depot/e89f0f58-076e-11ee-827e-0242ac110002/file
[2/3] (66.67%) csum: /mnt/dsk/var/data/depot/0f1a60a6-076f-11ee-a200-0242ac110002/file
[3/3] (100.00%) csum: /mnt/dsk/var/data/depot/55639ca8-076f-11ee-a315-0242ac110002/file
Total files: 3
Total extent hashes: 3
Loading only duplicated hashes from hashfile.
Found 3 identical extents.
Simple read and compare of file data found 1 instances of extents that might benefit from deduplication.
Showing 3 identical extents of length 209.8M with id 54f11aa1
Start Filename
0.0 "/mnt/dsk/var/data/depot/e89f0f58-076e-11ee-827e-0242ac110002/file"
0.0 "/mnt/dsk/var/data/depot/0f1a60a6-076f-11ee-a200-0242ac110002/file"
0.0 "/mnt/dsk/var/data/depot/55639ca8-076f-11ee-a315-0242ac110002/file"
Using 1 threads for dedupe phase
[0x56351b1f30c0] (1/1) Try to dedupe extents with id 54f11aa1
[0x56351b1f30c0] Add extent for file "/mnt/dsk/var/data/depot/e89f0f58-076e-11ee-827e-0242ac110002/file" at offset 0.0 (3)
[0x56351b1f30c0] Add extent for file "/mnt/dsk/var/data/depot/0f1a60a6-076f-11ee-a200-0242ac110002/file" at offset 0.0 (4)
[0x56351b1f30c0] Add extent for file "/mnt/dsk/var/data/depot/55639ca8-076f-11ee-a315-0242ac110002/file" at offset 0.0 (5)
[0x56351b1f30c0] Dedupe 2 extents (id: 54f11aa1) with target: (0.0, 209.8M), "/mnt/dsk/var/data/depot/e89f0f58-076e-11ee-827e-0242ac110002/file"
Kernel processed data (excludes target files): 419.5M
Comparison of extent info shows a net change in shared extents of: 629.3M
Après deduplication :
df -h .
Filesystem Size Used Avail Use% Mounted on
/dev/loop0 10G 219M 9,3G 3% /mnt/dsk
On a ainsi gagné pas moins de 419.5M !
Autres points intéressant de Duperemove
:
- Vous n’utilisez pas btrfs ou voulez avoir une idée de l’espace gagné, il est possible de lancer duperemove en mode détection seulement.
- Changer la taille des blocs (
-b
) permet de prendre en compte les fichiers plus petit, par exemple les preview dans le cas de Tracim. Duperemove
permet d’utiliser un hashfile qui évite de devoir recalculer les fichiers déjà lus, attention néanmoins à la taille du hashfile.
Aller plus loin…
La solution Duperemove
se conjugue bien avec le fonctionnement de Tracim, mais comment peut-on faire autrement ?
Quelles solutions les autres logiciels utilisent pour conserver un historique sans surcharger les disques ?
Nextcloud : De ce que je comprends de l’approche de nextcloud sur ce genre de problématique, elle consiste à tenter de réduire le nombre de versions sauvegardées ainsi le versionnage de nextcloud n’est à ce sens pas très fiable dans une logique d’archivage, une approche hybride à base de version par etiquette pour une gestion semi-automatique associé ou non ne sorte d’IA ou d’algorithme un peu malin pourrait faire l’affaire afin de limiter les versions stockée tout en gardant l’essentiel de l’historique.
Gestion de version : L’approche des logiciels de gestion de versions comme git est intéressante et est clairement optimale en espace de stockage pour du fichier texte. Elle permet réellement de l’archivage, de plus le principe de pouvoir associer un texte à une modification commit, permet de s’y retrouvé facilement. Néanmoins l’approche ne se conjugue pas très bien avec du stockage de fichier binaire.
Voili Voilà ! 😀