Btrfs Administration

Btrfs Administration

Im Folgenden werden einige Befehle zur Verwaltung eines Btrfs Dateisystems aufgeführt, welche üblicherweise zum Einsatz kommen.

Zur besseren Lesbarkeit dieses Artikels folgen wir der Namenskonvention, dass Btrfs-Subvolumes immer mit einem @ beginnen. Ebenfalls zur besseren Lesbarkeit wird angenommen, dass die Befehle im Folgenden von dem Benutzer root ausgeführt werden. Dies lässt sich auf Debian-basierten Systemen auch erreichen, indem einem Befehl ein sudo  vorangestellt wird. Finden die Wartungsarbeiten mittels Wartungszugang über ein Netzwerk statt, so ist insbesondere aufgrund der Dauer umfangreicherer Schreib-/Leseoperationen die Verwendung von screen empfehlenswert, um Seiteneffekten bei einem Abbruch der Netzwerkverbindung vorzubeugen.

Da Btrfs ein vergleichsweise junges Dateisystem ist, sollte man auf eine halbwegs aktuelle Kernel-Version achten bzw. behelfsweise darauf achten, dass wichtige Updates verfügbar sind und nachgezogen werden. Btrfs ist bislang von dessen Entwicklern nicht als vollumfänglich stabil erachtet worden, insofern sollte man es nur bedingt auf Produktionssystemen einsetzen bzw. sollte man sich über entsprechende Risiken im Klaren sein.

Balancierung eines Btrfs Dateisystems

Btrfs-Dateisysteme halten neben den Nutzdaten, also den Dateiinhalten, auch Metadaten in abgetrennten Bereichen vor. Bei einer Partitionsgröße von etwa 3 TB stellen sich die bereits verwendeten Bereiche im Realbetrieb beispielsweise wie folgt dar:

mount /dev/sdX1 /mnt
btrfs filesystem df /mnt

Data, single: total=894.00GiB, used=892.07GiB
System, single: total=32.00MiB, used=108.00KiB
Metadata, single: total=9.00GiB, used=6.98GiB
GlobalReserve, single: total=512.00MiB, used=0.00B

sudo btrfs filesystem usage /mnt

Overall:
    Device size:                   2.73TiB
    Device allocated:            902.03GiB
    Device unallocated:            1.85TiB
    Device missing:                  0.00B
    Used:                        899.06GiB
    Free (estimated):              1.85TiB      (min: 1.85TiB)
    Data ratio:                       1.00
    Metadata ratio:                   1.00
    Global reserve:              512.00MiB      (used: 0.00B)

Data,single: Size:893.00GiB, Used:892.07GiB
   /dev/sdX1         893.00GiB

Metadata,single: Size:9.00GiB, Used:6.99GiB
   /dev/sdX1           9.00GiB

System,single: Size:32.00MiB, Used:104.00KiB
   /dev/sdX1          32.00MiB

Unallocated:
   /dev/sdX1           1.85TiB

Von Zeit zu Zeit stößt Btrfs bezüglich eines der Segmente an dessen zugewiesene Grenzen und vermeldet eine volle Festplatte oder sonstige Seiteneffekte. Um dies zu vermeiden bzw. um gar nicht erst in die Nähe dieser Grenzen zu stoßen, sollte man regelmäßig eine sogenannte Balancierung durchführen. Mittels Balancierung werden insbesondere nicht mehr benutzte, aber bereits zugewiesene Bereiche wieder verfügbar und insbesondere anderen Segmenten zugänglich gemacht. Auch bezüglich einer abnehmenden Geschwindigeit kann eine Balancierung Abhilfe verschaffen, insbesondere da sie einer Fragmentierung des Dateisystems vorbeugt. Zu empfehlen ist die Balancierung daher insbesondere periodisch monatlich oder nach umfangreicheren Schreiboperationen bzw. Löschungen.

Eine Balancierung eines Btrfs-Dateisystems lässt sich erreichen mit

mount /dev/sdX1 /mnt
btrfs balance start /mnt

Subvolume anlegen und löschen

Der Wurzelknoten eines Btrfs Dateisystem wird nicht unbedingt automatisch per /etc/fstab gemountet. Stattdessen empfiehlt es sich, in der Wurzel eines Btrfs Dateisystems diverse Subvolumes anzulegen, die man dann wiederum per /etc/fstab oder auch manuell mounten kann. Initial kann man die isolierte Subvolumes wie folgt anlegen:

mount /dev/sdX1 /mnt  #ohne Kompression mounten
mount -o compress=lzo /dev/sdX1 /mnt  #mit Kompression mounten
cd /mnt
btrfs subvolume create @root
btrfs subvolume create @home

Diese Subvolumes lassen sich dann wiederum wie folgt in der /etc/fstab mounten:

/dev/sdX1 /               btrfs   defaults,subvol=@        0       1
/dev/sdX1 /home           btrfs   defaults,subvol=@home    0       2

Man kann beim Mounten auch gleich die Kompression aktivieren:

/dev/sdX1 /               btrfs   defaults,subvol=@,compress=lzo        0       1
/dev/sdX1 /home           btrfs   defaults,subvol=@home,compress=lzo    0       2

Subvolumes lassen sich jedoch auch in jedem beliebigen Verzeichnis eines Btrfs-Dateisystems anlegen, insbesondere auch innerhalb eines Subvolumes. Ein gesondertes bzw. mehrfaches Mounten des Btrfs-Dateisystems, wie oben beschrieben, ist nicht notwendig, erlaubt aber eben den Zugriff auf die Wurzel des Btrfs-Dateisystems. Ganz ohne Einbindung können subvolumes jedoch nicht erstellt werden, insofern muss das Btrfs mindestens auf einem Mount-Point eingehängt sein, um darin Subvolumes anlegen zu können.

Gelöscht werden kann ein Subvolume inklusive aller Inhalte (rekursiv) wie folgt:

btrfs subvolume delete @test

Hierbei ist zu bemerken, dass das Löschen eines isolierten Btrfs-Subvolumes extrem schnell ist, insbesondere müssen Dateien und Verzeichnisse nicht einzeln gelöscht werden. Dauert das Löschen eines Btrfs-Subvolumes lange, dann kann dies daran liegen, dass Varianten des Btrfs-Subvolumes in Form von Snapshots existieren, also ein Snapshot von dem Subvolume erstellt wurde oder das Subvolume selbst ein Snapshot eines anderen Subvolumes ist.

Fragmentierung und Defragmentierung eines Btrfs Dateisystems

Da Btrfs ein Copy-on-Write Dateisystem ist, sollte man sich zunächst klar machen, dass bei Btrfs bei der Erstellung eines Snapshots zunächst praktisch nicht mehr auf die Festplatte geschrieben wird, als ein Verweis auf ein anderes Subvolume. Erst wenn die beiden Subvolumes aufgrund von Änderungen auseinanderdriften, legt Btrfs eine Kopie eines Datenblockes an bzw. schreibt Btrfs einen neuen Datenblock "an das Ende" des bis dahin genutzten Teils der Partition. Um nicht extra prüfen zu müssen, in welchen Subvolumes ein Datenblock enthalten ist, schreibt Btrfs einfachkeitshalber alle Änderungen ans Ende des bis dahin genutzten Teils der Partition. Man kann sich klar machen, dass dies zu sehr vielen Fragmenten führen kann, bereits beim abwechselnden Schreiben in zwei Dateien sollte mit Fragmenten zu rechnen sein.

Bei konventionellen Festplatten führen die Fragmente zu Sprüngen, die die Festplattenköpfe über die Partition zu absolvieren haben, um die gewünschten Festplattenzugriffe abzuarbeiten. Diese Sprünge machen nicht nur Lärm, sie dauern auch Zeit und verlangsamen die Festplattenzugriffe, was unerwünscht ist. Bei SSDs hat man beide Probleme zwar nicht, weil es bei SSDs keine Festplattenköpfe gibt, jedoch wird ein fragmentiertes Btrfs-Dateisystem selbst bei SSDs langsamer, da die Fragmentierung auch andernorts zu Overhead führt: Es sind mehr Blöcke von den Referenzen auf die Nutzdaten betroffen, außerdem müssen die Fragmente verarbeitet werden (CPU, Arbeitsspeicher). Im Versuchslabor konnte selbst bei Verwendung einer SSD eine signifikante Verschlechterung der Performance festgestellt werden, die sich auf dem verwendeten Desktop-System jedoch erst nach ca. 2-3 Jahren bemerkbar machte. Bei SSDs sollte man allerdings aufgrund der begrenzten Überschreibzyklen sparsam mit Schreibzugriffen sein, insbesondere mit Schreibzugriffen bei Durchführung einer Defragmentierung. In längeren Abständen (ca. 1-2 Jahre) sollte man jedoch auch bei SSDs über eine Defragmentierung nachdenken. Über die Lebenszeit einer SSD machen 5-10 zusätzliche Überschreibzyklen keinen nennenswerten Unterschied, in der Performance eines Btrfs-Dateisystems, und damit der Benutzbarkeit, allerdings schon.

Mit diesen Vorbemerkungen kann man sich ableiten, dass man Fragmentierungen behalten möchte, die es ermöglicht, redundante Datenspeicherung über mehrere Subvolumes zu vermeiden. Insbesondere reduziert sich der zusätzlich benötigte Speicherplatz für einen Snapshot zunächst auf Null. Divergieren die Subvolumes anschließend, so wird nur für die Deltas, also die Unterschiede, Speicherplatz benötigt. Hat man also voneinander mittels Snapshots abgeleitete Subvolumes, sollte man eine Defragmentierung vermeiden, denn diese würde die dank CoW mittels Fragmentierung vermiedenen Duplikate tatsächlich physisch ausschreiben.

Liegt jedoch nur ein isoliertes Subvolume vor, von dem kein Subvolume abgeleitet ist, und das auch selbst nicht von einem anderen Subvolume abgeleitet ist, dann kann man eine Defragmentierung durchführen, ohne eine Duplizierung der Daten befürchten zu müssen. Um sicherzustellen, dass ein Subvolume tatsächlich isoliert ist, sollte man nicht vergessen, das oft nicht sichtbare Wurzelverzeichnis eines Btrfs-Dateisystems zu mounten. Speziell Ubuntu legen selbsttätig Snapshots bei Distributionsaktualisierungen an, z. B. ein Snapshot @apt-snapshot-release-upgrade-xenial des Subvolumes @ im Btrfs-Wurzelverzeichnis ist dem Benutzer oft nicht bekannt, da nur die Verzeichnisstruktur unterhalb von @ mittels /etc/fstab auf / gemountet wird.

Auch sollte man einbeziehen, dass Subvolumes (inklusive davon abgeleitete Snapshots) in Subvolumes liegen können. Da die Defragmentierung rekursiv durchlaufen wird, könnte man innerhalb eines isolierten Subvolumes bezüglich darin enthaltener Subvolumes wieder Duplikate produziert.

Einzelne Dateien, ganze Verzeichnisse oder Subvolumes lassen sich wie folgt defragmentieren:

btrfs filesystem defragment -c /mnt/@mysubvol/mydir/myfile
btrfs filesystem defragment -c /mnt/@mysubvol/mydir
btrfs filesystem defragment -c /mnt/@mysubvol

Die Defragmentierung ist nur auf einem gemounteten Dateisystem möglich. Btrfs lässt zu, dass während der Defragmentierung von beliebigen Prozessen gelesen und geschrieben wird. Für diese Prozesse ist eine parallel laufende Defragmentierung insofern transparent. Btrfs lässt außerdem mehrfache mounts eines Dateisystems zu, sodass man auch das ansonsten unsichtbare Wurzelverzeichnis zusätzlich zu den mounts der für den Produktionsbetrieb nötigen mounts mounten kann.

Um zukünftige Fragmentierung etwas einzudämmen, sollte man darauf achten, dass jederzeit genug freier und benutzbarer Speicherplatz auf dem Btrfs-Dateisystem zur Verfügung steht, insbesondere wäre periodisch eine Balancierung durchzuführen.

Automatische Defragmentierung eines Btrfs Dateisystems

Es gibt auch eine mount-Option autodefrag zur automatischen Defragmentierung. Bei schreibenden Zugriffen kann diese Option jedoch zusätzliche Zugriffe nach sich ziehen, sodass sich die Performance verschlechtert. Zudem hat man oben genannte Probleme bezüglich ungewollter Defragmentierung. Insofern eignet sich die mount-Option autodefrag nur bedingt, also in Spezialfällen.

Mittels mount-Befehl lässt sich die Option autodefrag wie folgt benutzen:

mount -o autodefrag /dev/sdX1 x

Auch mittels /etc/fstab kann die Option autodefrag aktiviert werden:

/dev/sdX1 /home           btrfs   defaults,subvol=@home,autodefrag    0       2

Transparente Kompression eines Btrfs Dateisystems

Btrfs verwaltet Kompressionseigenschaften auf Ebene bereits geschriebener Daten: Wenn Daten des Filesystems komprimiert sind, merkt Btrfs das und dekomprimiert die Datei beim lesen automatisch, und insbesondere transparent. Insofern ist beim Lesen nichts besonderes zu beachten.

Interessanter wird es allerdings beim Schreiben: Damit Daten komprimiert geschrieben werden, muss man bereits beim Mounten die Kompression aktivieren, indem man die Mount-Option compress=gzip oder compress=lzo setzt (wobei gzip default ist und lzo naturgemäß schneller als gzip ist):

Manuell mounten:

mount -o compress=lzo /dev/sdX1 x

Automatisch mit /etc/fstab mounten:

/dev/sdX1 /home           btrfs   defaults,subvol=@home,compress=lzo    0       2

Ist die Kompression aktiviert, werden alle zu schreibenden Daten, sofern komprimierbar, komprimiert geschrieben. Da Btrfs ein Copy-on-Write Dateisystem ist, ist zu beachten, dass im Wesentlichen nur Änderungen bzw. neu zu schreibende Daten komprimiert werden. Insofern ist es sogar vorstellbar, dass nach Aktivierung der Kompression nur Änderungen an einer Datei komprimiert werden, zuvor geschriebene Inhalte der Datei jedoch unverändert, also unkomprimiert, bleiben.

Um eine unkomprimierte Datei nachträglich zu komprimieren, kann man diese während einer Defragmentierung mittels der Option -c online (bei gemountetem Dateisystem) komprimieren:

btrfs filesystem defragment -c myfile.txt

Man kann auch ein ganzes Subvolume beim Defragmentieren komprimieren:

btrfs filesystem defragment -c @mysubvol

Auch hier muss man allerdings wieder aufpassen und die Eigenheiten eines Copy-on-Write Dateisystems beachten: Handelt es sich bei den zu defragmentierenden Datenbeständen um Datenbestände, zu denen Snapshots mit Varianten dieser Daten existieren, dann vermeidet Btrfs das Ausschreiben von Redundanzen, sodass Fragmentierungen entstehen und diesbezüglich auch erwünscht sind. Mittels Defragmentierung wird wiederum erreicht, dass eine Datei zusammenhängend auf der Festplatte liegt, wodurch jede Variante einer Datei dann komplett ausgeschrieben wird. Bei ansonsten kleinen Deltas zwischen einer Datei, die in n Varianten in n Subvolumes vorliegt, kann Defragmentierung fast zur Ver-n-fachung des beanspruchten physikalischen Speicherplatzes auf der Festplatte führen, was wiederum unerwünscht sein dürfte. Um dies zu vermeiden, sollte man nur Datenbestände defragmentieren, von denen keine Varianten in anderen Subvolumes existieren.

Die Defragmentierung (inklusive Kompression) läuft dann transparent im Hintergrund ab. Über den Status der Defragmentierung kann man sich informieren mit

btrfs filesystem defragment