Compression de flux à la volée qui ne déborde pas sur les ressources matérielles?

23

J'ai 200 Go d'espace disque libre, 16 Go de RAM (dont ~ 1 Go sont occupés par le bureau et le noyau) et 6 Go de swap.

J'ai un SSD externe de 240 Go, avec 70 Go utilisés 1 et le reste libre, que je dois sauvegarder sur mon disque.

Normalement, je voudrais dd if=/dev/sdb of=Desktop/disk.imgd'abord le disque, puis le compresser, mais créer l'image en premier n'est pas une option car cela nécessiterait beaucoup plus d'espace disque que moi, même si l'étape de compression entraînera l'écrasement de l'espace libre de sorte que le l'archive finale peut facilement tenir sur mon disque.

ddécrit dans STDOUT par défaut, et gzippeut lire depuis STDIN, donc en théorie je peux écrire dd if=/dev/sdb | gzip -9 -, mais il gzipfaut beaucoup plus de temps pour lire les octets que ce qui ddpeut les produire.

De man pipe:

Les données écrites à l'extrémité d'écriture du canal sont mises en mémoire tampon par le noyau jusqu'à ce qu'elles soient lues à l'extrémité de lecture du canal.

Je visualise un |comme étant un vrai tube - une application insérant des données et l'autre retirant les données de la file d'attente du tube le plus rapidement possible.

Que se passe-t-il lorsque le programme sur le côté gauche écrit plus de données plus rapidement que l'autre côté du tuyau peut espérer les traiter? Cela entraînera-t-il une utilisation extrême de la mémoire ou des échanges, ou le noyau essaiera-t-il de créer une FIFO sur le disque, remplissant ainsi le disque? Ou échouera-t-il simplement SIGPIPE Broken pipesi le tampon est trop volumineux?

Fondamentalement, cela se résume à deux questions:

  1. Quelles sont les implications et les résultats de l'introduction de plus de données dans un tube que ce qui est lu à la fois?
  2. Quel est le moyen fiable de compresser un flux de données sur le disque sans placer l'intégralité du flux de données non compressé sur le disque?

Remarque 1: je ne peux pas simplement copier exactement les 70 premiers Go utilisés et m'attendre à obtenir un système ou un système de fichiers fonctionnel, en raison de la fragmentation et d'autres choses qui nécessiteront l'intégralité du contenu.

chat
la source
Pourquoi voudriez-vous sauvegarder un système de fichiers entier comme ça, au lieu de simplement des répertoires d'utilisateurs, et peut-être une liste de logiciels non standard installés?
jamesqf
5
@jamesqf Eg. car il est beaucoup plus facile de restaurer ...
deviantfan
4
@jamesqf Parce qu'alors, j'obtiens également le secteur de démarrage et la partition de swap, afin de pouvoir recréer le disque exactement au lieu d'avoir un milliard de fichiers ennuyeux.
cat
3
Astuce aléatoire: regardez au lzoplieu de gzip; il se comprime beaucoup plus rapidement avec seulement un taux de compression légèrement inférieur. Je le trouve idéal pour les images de disque où la vitesse de compression peut être un véritable goulot d'étranglement.
marcelm
1
"Que se passe-t-il lorsque le programme sur le côté gauche écrit plus de données plus rapidement que l'autre côté du tuyau peut espérer les traiter?" Le noyau provoquera la mise en veille du processus d'écriture jusqu'à ce qu'il y ait plus de place dans le tuyau.
Tavian Barnes

Réponses:

16

Techniquement, vous n'avez même pas besoin dd:

gzip < /dev/drive > drive.img.gz

Si vous utilisez dd, vous devriez toujours aller avec plus grand que blocksize par défaut comme dd bs=1Mou subir l'enfer syscall ( ddde » la blocksize par défaut est de 512 octets, car il read()s et write()s qui est 4096syscalls par MiB, trop frais généraux).

gzip -9utilise beaucoup plus de CPU avec très peu à montrer pour cela. Si cela gzipvous ralentit, abaissez le niveau de compression ou utilisez une méthode de compression différente (plus rapide).

Si vous effectuez des sauvegardes basées sur des fichiers au lieu d' ddimages, vous pouvez avoir une logique qui décide de compresser ou non (cela ne sert à rien pour différents types de fichiers). dar( taralternative`) est un exemple qui a des options pour le faire.

Si votre espace libre est ZÉRO (car c'est un SSD qui retourne zéro de manière fiable après TRIM et que vous avez exécuté fstrimet déposé des caches), vous pouvez également utiliser ddavec conv=sparseflag pour créer une image clairsemée montable en boucle non compressée qui utilise zéro espace disque pour les zones nulles . Nécessite que le fichier image soit sauvegardé par un système de fichiers qui prend en charge des fichiers clairsemés.

Alternativement, pour certains systèmes de fichiers, il existe des programmes capables de n'imaginer que les zones utilisées.

frostschutz
la source
1
"Si vous utilisez dd, vous devriez toujours choisir une taille de bloc plus grande que celle par défaut dd bs=1M" - Vous pouvez, mais ne vous attendez pas à trop. Sur mon PC, ddfera environ 2 Go / s avec des blocs de 512 octets. Ce ne sera pas le goulot d'étranglement; gzipsera.
marcelm
@marcelm Nous ne savons jamais quel type de machine les gens utilisent. Si vous avez dd2 Go / s avec des blocs de 512 octets, je serais surpris s'il n'atteignait pas 100% du cœur du processeur dans le processus. Maintenant, si votre boîte est un quadcore qui reste inactif de toute façon, vous ne remarquerez peut-être pas de différence. Mais tout le monde le fait toujours.
frostschutz
9
Soupir. Chaque fois que la ddtaille de bloc est mentionnée, les gens viennent taquiner. gzipêtre intensif en cpu faisait également partie de ma réponse, d'accord? Et désolé, je ne suis pas d'accord avec "négligeable". Il ne peut ajouter que 1 à 2 par concert avec gzip -9(mais cela équivaut toujours à des minutes lors du traitement de centaines de concerts), mais en suivant vos conseils, lzop -1c'est 1 par concert contre 4 par concert. Testé sur une pomme de terre (vserver monocœur). L'ajout d'une taille de bloc saine ddne coûte rien et n'a aucun inconvénient. Ne pique pas. Simplement fais-le. ymmv
frostschutz
19

ddlit et écrit des données un bloc à la fois, et il n'a qu'un seul bloc en attente. Alors

valgrind dd if=/dev/zero status=progress of=/dev/null bs=1M

montre qui ddutilise environ 1 Mo de mémoire. Vous pouvez jouer avec la taille du bloc et la laisser tomber valgrindpour voir l'effet sur ddla vitesse de.

Lorsque vous vous connectez gzip, ddralentit simplement pour correspondre à gzipla vitesse. Son utilisation de la mémoire n'augmente pas et n'entraîne pas le stockage du tampon sur le disque par le noyau (le noyau ne sait pas comment faire, sauf via swap). Un tuyau cassé ne se produit que lorsque l'une des extrémités du tuyau meurt; voir signal(7)et write(2)pour plus de détails.

Ainsi

dd if=... iconv=fullblock bs=1M | gzip -9 > ...

est un moyen sûr de faire ce que vous recherchez.

Lors du piping, le processus d'écriture finit par être bloqué par le noyau si le processus de lecture ne suit pas. Vous pouvez le voir en exécutant

strace dd if=/dev/zero bs=1M | (sleep 60; cat > /dev/null)

Vous verrez que ddlit 1 Mo, puis émet un write()qui reste là en attente pendant une minute pendant l' sleepexécution. C'est ainsi que les deux côtés d'un tube s'équilibrent: le noyau bloque l'écriture si le processus d'écriture est trop rapide et il bloque la lecture si le processus de lecture est trop rapide.

Stephen Kitt
la source
1
C'est plutôt cool. Par quel mécanisme ddsait-on ralentir pour correspondre à gzipla vitesse? Il est automatique, comme par le noyau, ou calcule-t-il à partir des métadonnées sur son descripteur de fichier de sortie?
cat
9
@cat C'est automatique; ddappelle write()pour mettre des données dans le canal. write()transfère en fait le contrôle au noyau afin qu'il puisse manipuler la mémoire du canal. Si le noyau voit que le tuyau est plein, il attendra ("bloquer") jusqu'à ce que le tuyau ait assez de place. Ce n'est qu'alors que l' write()appel se terminera et transférera le contrôle vers dd, qui réécrira ensuite les données dans le canal.
marcelm
9

Il n'y a pas d'implications négatives autres que les performances: le canal a un tampon, qui est généralement de 64 Ko, et après cela, une écriture dans le canal se bloque simplement jusqu'à ce qu'il gziplit plus de données.

Ulrich Schwarz
la source
8

Répondre à la question réelle de savoir comment cela fonctionne: "que se passe-t-il si le programme sur le côté gauche écrit plus de données plus rapidement que l'autre côté du tuyau peut espérer les traiter?"

Cela n'arrive pas. Il y a un tampon assez petit et de taille limitée dans le tuyau; voir Quelle est la taille du tampon de tuyau?

Une fois que le tampon de canal est plein, le programme émetteur se bloque . Lorsqu'il effectue un appel en écriture, le noyau ne rendra pas le contrôle au programme tant que les données n'auront pas été écrites dans le tampon. Cela donne au programme de lecture le temps CPU pour vider le tampon.

pjc50
la source
3

Peut-être n'avez-vous besoin que des fichiers, puis utilisez tar. Vous pouvez remplir avec des zéros les blocs qui ne contiennent pas tout ce que vous voulez, quelqu'un a déjà posé une question à ce sujet. Effacez l'espace inutilisé avec des zéros (ext3, ext4)

Ensuite, il y a pigzce qui est généralement plus rapide que gzip.

yt7b97q-
la source