2024-07-15
Im Folgenden ist "Host" der Rechner, auf dem viele virtuelle Maschinen ("Gäste") laufen. Es wird mehrfach von Nullen die Rede sein, womit binäre Nullen, also Bytes mit dem Wert 0x00 gemeint sind.
Die Festplatte eines Gastes ist i.d.R. eine Datei. Es wäre große Verschwendung, den verfügbaren Platz eines Hosts komplett auf die Gäste aufzuteilen - z.B. eine 1000GB-Partition auf dem Host mit zehn 100GB-Dateien voll zu packen, damit die Clients notfalls so viel benutzen können, obwohl ihnen typischerweise je 20 GB reichen sollten und man somit meist Platz für bis zu 50 Gäste hätte.
Das RAW-Format benötigt1 für eine 100GB-Datei auch 100GByte auf der Host-Festplatte. Es empfiehlt sich aber das QCOW2-Format zu verwenden, da dort erst einmal nur der belegte Platz des Gastes benötigt wird - z.B. 20 GByte. Der Gast "sieht" aber die konfigurierten 100 GByte und kann diese auch verwenden. Dabei wächst die Datei auf dem Host mit - bis die 100GByte erreicht sind. Da dieser Extremfall i.d.R. nicht auftritt, kann man mit etwas Reserve den Gästen in Summe sehr viel mehr Plattenplatz versprechen, als insgesamt vorhanden ist.
Eine früher oft beschriebene Vorgehensweise basiert auf dem Wissen, dass im Gast gelöschte Dateien zwar nicht mehr im Verzeichnis auftauchen und ihre Datenblöcke irgendwann überschrieben werden, aber vorläufig noch auf der Festplatte vorhanden sind. Überschreibt man den gesamten als frei deklarierten Platz mit Nullen, so sind die Dateien endgültig vernichtet. So geht man dazu vor:
dd if=/dev/zero of=delme.soon bs=1M; sync; rm delme.soon; sync
Nachteil: In unserem Beispiel werden sinnlos 80GB Nullen geschrieben,
dann die 100GB-Datei eingelesen und als neue 20GB-Datei
geschrieben.
Nachteil: Der komplette "versprochene" Platz wird zumindest kurzfristig
benötigt!
Nachteil: Für einige Minuten ist der Gast (ggf. ein wichtiger Server)
nicht benutzbar. Dienste sollten heruntergefahren sein um Abstürze zu
vermeiden.
Vorteil: keine Unterstützung des Gast-Betriebssystems nötig (man könnte
die Nullen auch remote auf die virtuelle Platte schreiben oder die
virtuelle Maschine vorübergehend mit einem anderen Betriebssystem
booten.)
Die Betriebssysteme haben für SSDs lernen müssen, wie man den nicht benutzten Platz an den Datenträger meldet. So können die Speicherstellen freigegeben werden und für das gleichmäßigere Verteilen von Schreibzugriffen genutzt werden können. Der Vorgang wird meist TRIM, Trimmen oder discard genannt. Dies nutzen wir auf dem Gast.
Andererseits können unter Linux Dateien Lücken haben, die logisch mit Nullen “gefüllt” sind, aber keinen Platz auf der Festplatte benötigen. Dies nutzen wir auf dem Host. Solche Dateien nennt man Sparse-Files.
So läuft das Zusammenspiel ab:
⇒ Auf dem Gast wird eine Datei gelöscht (in seiner Festplattenverwaltung wird der Platz, z.B. Block 666777, als frei gekennzeichnet)
⇒ per Trim wird der frei werdende Speicher (z.B. einmal täglich) an die virtuelle Festplatte gemeldet (die Info, dass 666777 nicht mehr benötigt wird, wird an die virtuelle Festplatte weitergereicht)
⇒ Auf dem Host erhält KVM diese Information und gibt den entsprechenden Speicher in der Festplattendatei auf dem Host frei (KVM belegt keinen Platz mehr für Block 666777, der in der Datei als Block 4545 gespeichert war)
⇒ Die Festplattendatei des Gastes hat nun eine Lücke mehr, und belegt somit auf der Host-Festplatte weniger Platz. (Das Filesystem des Hosts hat die Information erhalten, dass in der Festplattendatei der Block 4545 mit Nullen belegt ist und braucht dafür so gut wie keinen Platz mehr auf der echten Festplatte.)
Damit dies funktioniert muss der Gast trimmen können und KVM die Freigabe auch verarbeiten:
Die virtuelle Festplatte für den Gast muss eine SCSI-Festplatte sein
(ggf. nachträglich geändert - Backup gemacht?), da KVM nur bei dieser
den “discard”-Mechanismus beherrscht. Wenn möglich gleich bei
Details/Erweiterte Optionen/Mode verwerfen den Eintrag
unmap
wählen.
KVM muss ggf. noch angewiesen werden, wie es mit freigegebenen Speicherbereichen umgehen soll: Der Speicher soll im Filesystem des Host-Betriebssystems freigegeben werden - Fachbegriff hier “unmap”. Dies kann man in der Konfiguration des virtuellen Speichers im virt-manager anklicken - s.o..
Früher musste man in der KVM-Konfigurationsdatei einen weitereren Eintrag machen (während der Gast heruntergefahren ist):
mit virsh edit Gastname
die Konfigurationsdatei
öffnen, (vim: mit Taste i in den Einfügemodus wechseln)
folgende Zeile suchen
<driver name='qemu' type='qcow2'/>
und mit discard='unmap'
ergänzen:
<driver name='qemu' type='qcow2' discard='unmap'/>
Info: ca. zwei Zeilen darunter steht, dass es ein SCSI-Device ist.
Je nach Editor (vim: ESC : w q) speichern und verlassen.
Nun den Gast wieder starten.
sudo fstrim -av
ls -hls
, siehe unten)fstrim -a
)
oder besser fstrim.timer
mit
sudo systemctl unmask fstrim.timer && sudo systemctl start fstrim.timer
).Man muss natürlich damit rechnen, dass obiges Vorgehen immer auch einen Leistungsverlust bei den Festplattenzugriffen bedeutet. Sparse-Files haben nun einmal den Ruf, dass sie im längeren Gebrauch zu einer Fragmentierung der Host-Festplatte führen. Das stört aber nur Benutzer einer echten Festplatte. Mit SSDs ist das kein praktisches Problem. Außerdem kann man jederzeit die unten beschriebene Konvertierung in eine neue Datei durchführen, wodurch auch eine Fragmentierung behoben werden dürfte.
Vorsicht: Bei einer Datensicherung mit z.B. cp
oder
scp
werden die freien Bereiche voll als Nuller übertragen.
rsync
kann es besser oder man sichert gleich eine
optimierte qcow2
datei. Siehe unten:
Merke: Das qcow2-Format von KVM erzeugt "sparse"-Dateien. Diese
können & werden Lücken haben. Unbenutzter Platz kann logisch als mit
Nullen gefüllt angesehen werden. Dies wird dem Host-Betriebssystem
(genauer: EXT4-Treiber) mitgeteilt, der das entsprechend vermerkt und
dafür keinen Festplattenplatz benötigt. Man kann übrigens auch beliebige
Dateien, die Blöcke mit Nullen enthalten, verkleinern, in dem man
fallocate -d dateiname
aufruft.
ls -hls
du *.qcow2*
So unterscheidet man nun den logischen und den realen Platzbedarf:
Der ls
-Befehl liefert sowohl die logische Größe, als auch
den tatsächlich belegten Platz. Auch du
meldet die
tatsächliche Belegung.
Die logische Größe ist wichtig, falls man ein Backup ohne weitere Vorkehrungen über’s Netz schiebt: Diese Größe wird übertragen, auch wenn sehr viele Nullen dabei sind. Gezippt sollte das kaum ein Problem sein, kostet aber Zeit. Rsync kann wie immer auch dieses Problem lösen.
Enthält eine QCOW2-Datei Leerstellen (echte Nullen oder Lücken via sparse-file), so kann man die Datei verkleinern lassen, in dem man sie in eine neue Datei konvertiert. Dabei werden die Leerstellen im qcow2-Format selbst abgebildet und nicht auf Basis von Sparse-Files.
Dies erledigt bei heruntergefahrenem Gast folgende Befehlsfolge (Backup vorhanden?):
mv gast.qcow2 gast.org
qemu-img convert -O qcow2 gast.org gast.qcow2
Dies kann man natürlich auch zum Zweck eines Backups machen:
qemu-img convert -O qcow2 gast.qcow2 /backup/ziel/pfad/gast.qcow2
Wer wirklich auf den Platzbedarf achtet, kann den
zusätzlichen Parameter -c
zum Komprimieren mitgeben. Dies
ist gerade bei Backups sinnvoll. Der Vorgang dauert auch mit mehreren
Prozessorkernen deutlich länger. Belegte Sektoren werden jetzt
komprimiert, beim späteren Überschreiben aber wieder unkomprimiert
abgelegt. Dies führt z.B. zu folgenden Einsparungen:
Bei zukünftigen Schreibzugriffen muss man nun mit leichten Tempoeinbußen rechnen.
Geht es jedoch mehr um Performance, so kann man
stattdessen beim Konvertieren den Parameter
-o preallocation=metadata
mit angeben. Das kostet wenig
echten Plattenplatz, legt aber bereits alle Metadaten der qcow2-Datei
an. Zukünftige Schreibzugriffe sollten entsprechend schnell sein. Ein
Vergleich fand sich hier.
Deutlich ausführlicher hier nachzulesen mit vielen weiteren englischen Quellen.
Hier eine ausführlichere englische Quelle zum Trimmen in KVM.