Inhaltsverzeichnis

KVM Thin Provisioning

Wie kann man den Festplattenspeicherplatz effizient verwalten? Dies beantwortet dieser Artikel.
Dabei 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.

Problem: Festplattenplatz

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.

Idee: Thin-Provisioning

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 zu den 100GByte. 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.

Methode 1: Festplatte füllen, dann leeren

Eine 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:

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…)

Methode 2: discard/TRIM

Hintergrund: Betriebssysteme haben für SSDs lernen müssen, dass man den nicht benutzten Platz an den Datenträger meldet, so dass 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.

Diese Fähigkeit des Gast-Betriebssystem nutzt man nun wie folgt:

  ⇒ Gast löscht eine Datei 
      (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)
  ⇒ KVM 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 hat 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:

Gast anpassen

Die virtuelle Festplatte für den Gast muss eine SCSI-Festplatte sein (ggf. nachträglich geändert - Backup gemacht?).
Dafür benötigt man unter Windows die stable Windows-Virtio-Treiber-CD von Fedora (z.B. im Nov. 2019 die Datei virtio-win-0.1.171.iso).

KVM ergänzen

In der KVM-Konfigurationsdatei muss ein weiterer Eintrag gemacht werden (während der Gast heruntergefahren ist):

<driver name='qemu' type='qcow2'/>
<driver name='qemu' type='qcow2' discard='unmap'/>

Gast vollenden

Nun den Gast wieder starten.

Nachbetrachtung

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.

Handwerkszeug

Test: Dateigrößen

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. Wie unterscheidet man nun den angeblichen und den realen Platzbedarf?

ls -hls

Der Befehl liefert sowohl die offizielle Größe, als auch den tatsächlich belegten Platz. Auch du *.qcow2 meldet die tatsächliche Belegung. Die offizielle 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…

Tipp: Konvertieren der QCOW2-Datei

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. 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 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 jedoch mit Tempoeinbußen rechnen. Geht es jedoch mehr um Performance, so kann man 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 findet sich hier.

Deutlich ausführlicher hier nachzulesen mit vielen weiteren englischen Quellen.

Hier eine ausführlichere englische Quelle zum Trimmen in KVM.

1)
hier kann natürlich die Festplattenverwaltung des Hosts selbst wieder optimieren…
2)
erfolgreich getestet mit Win10 1909 auf Debian Buster KVM mit virtio-TreiberCD 1.171
3)
z.B. auf Ubuntu-Xenial KVM mit mehreren Win10 1909 gelungen
4)
Datei in cron.weekly mit fstrim -a
5)
aktivieren von fstrim.timer mit sudo systemctl unmask fstrim.timer && sudo systemctl start fstrim.timer