Johannes Truschnigg - SRE & DevOps


Zur Suche ▼Zum Archiv ▼

Eintrag von 2010-10-04

Linux-md, LVM2 und ext4 - Online-Reshaping


Linux steckt heute als treibende Kraft in Home-Routern, Smartphones, Desktops, Servern und Supercomputern. Neben der lizenkostenfreien und quelloffenen Natur der Software sind auch ihre unvergleichliche Flexibilität und bestechende Modularität Gründe dafür. Dies schlägt auch in den Storage-Subsystemen durch und ist meine Motivation, meinen Homeserver mit Gentoo GNU/Linux als Betriebssystem zu verwenden. Vor ein paar Tagen habe ich diesem eine Speichererweiterung gegönnt: Statt vier 1500GB-Festplatten sind nun fünf verbaut, der verfügbare Bruttospeicherplatz beträgt nun stattliche 7500GB - hoffentlich genug für die nächsten zwei oder drei Jahre.

Auch wenn es in meiner Situation nicht unbedingt notwendig gewesen wäre, habe ich es mir zum Ziel gesetzt, die Erweiterung des Server ohne Downtime oder Reduktion der Verfügbarkeit über die Bühne zu bringen. Das bedeutet: wer auch immer Dienste, die der Server anbietet, nutzt, bemerkt nichts davon, dass auf diesem gerade Wartungsarbeiten durchgeführt werden. Alle Fileserveraktivitäten und dergleichen werden vor, während und nach der Erweiterung unterbrechungsfrei zur Verfügung gestellt.

Das ist auf Systemebene alles Andere als eine triviale Sache: Die neue Festplatte muss im laufenden Betrieb zuerst ins System selbst und dann in ein RAID-Array eingebunden werden. Dann muss das Volume Management-Subsystem darüber informiert werden, dass es nun eber mehr Platz auf dem RAID-Array verfügt, und am Ende will auch noch das darauf residierende Dateisystem entsprechend aufgeblasen werden. All das passiert, während Nutzer möglicherweise Daten vom Server lesen oder gar auf ihn schreiben. Zum Glück haben sich Heerscharen von Kernelhackern darüber Gedanken gemacht, wie man solche Anforderungen ohne Datenverlust erfüllen kann - was Administratoren viel Kopfzerbrechen spart. Einen Ansatz, eine solche Erweiterung unterbrechungsfrei durchzuführen, will ich in diesem Posting demonstrieren.

Das Anstecken einer neuen (SATA-)Festplatte zur Laufzeit ist mit einem aktuellen Kernel und einem modernen Controller kein Problem mehr: Kaum registriert der Controllertreiber Bewegung am Port, taucht die neue Disk auch schon unter einem neuen Device Node Name im /dev-Verzeichnis auf. Da mein md-RAID-Setup nicht rohe Festplatten direkt einbindet, sondern MBR-Partitionen als Grundbaustein für mein RAID5-Array benutzt, habe ich zuallererst das Partitionslayout einer existierenden Platte aus dem Verbund auf die neue, fünfte Platte (in meinem Fall /dev/sdf) repliziert:

# sfdisk -d /dev/sdb | sfdisk /dev/sdf

Zu beachten ist dabei, dass sfdisk nur mit MBR-Partitionen umgehen kann. Will man GPT-Partitionen, BSD Disklabels oder irgenwelche anderen Schemata verwenden, ist man auf das wesentlich mächtigere GNU parted oder andere, potenziell plattformspezifische Tools angewiesen. Das dadurch entstehende Blockdevice /dev/sdf1 macht man md (mein Array wird unter dem Node Name /dev/md1 angesprochen) durch zwei Aufrufe von mdadm schmackhaft:

# mdadm --add /dev/md1 /dev/sdf1
# mdadm --grow /dev/md1

Das erste Kommando bindet /dev/sdf1 als Spare Device in den Verbund ein, das zweite sorgt dafür, dass alle Spare Devices zu vollwertigen Member Devices und damit als Nettospeicherplatz (in Form von Blocks - noch nicht in einem Dateisystem!) verfügbar gemacht werden. Dies hat einen RAID Resync/Reshape zur Folge, der auch ganz ohne Last auf dem Array und je nach seiner Kapazität mehrere Stunden dauern kann. Bis auf eine Reduktion der Schreib- und Lesegeschwindigkeiten ist von der Operation sonst aber nichts zu spüren, den Fortschritt der Operation kann man jederzeit in der Datei /proc/mdstat überprüfen.

Danach soll das Logical Volume Management-Subsystem (LVM2) erfahren, dass es nun mehr Speicher zur Verwaltung zur Verfügung hat. Das RAID5-Array /dev/md1 - ein aus Sicht von LVM2 ganz normales Blockdevice wie jedes andere auch - ist ja gerade um 1.5TB gewachsen; das durch es gebildete Physical Volume (PV) aber wähnt sich immer noch die ursprüngliche Kapazität fassend. Diesen Umstand ändert man mit

# pvresize /dev/md1

Ohne zusätzliche Parameter lässt pvresize das PV immer auf die Größe des ganzen zugrundeliegenden Block Devices wachsen, in diesem Fall also um 1.5GB. Hierbei sind keine langwierigen Reshape-Operationen nötig, da nur Metadaten in den PV-Beschreibungsstrukturen geändert werden. Diese Änderung erfolgt augenblicklich. Freilich ist das Vergrößern des PV nicht das Ende vom Lied: Wahrend die Volume Group (VG), die auf dem PV residiert, noch automatisch mitwächst, muss auch das Logical Volume (LV), das das zu vergrößernde Dateisystem beinhaltet, einen Wachstumsschub hinlegen. Im Unterschied zu pvresize muss man seinem Analog fuer LVs, lvresize, allerdings auch sagen, wie groß genau das LV letztendlich werden soll. Hier kann man entweder mit einer groben Kapazitätsangabe (bspw. 14000M, 14G, 0.14T, ...) arbeiten, oder aber Physical Extents (PE) als Einheit verwenden. PEs sind für LVM ungefähr das, was für Festplatten Sektoren sind: Die kleinsten individuell ansprechbaren Speicherblöcke, die vom System bearbeitet werden können. Um herauszufinden, wie viele PEs die gewachsene VG beinhaltet (und wie viele daher maximal für die LV konsumierbar sind), wirft man einen Blick in die Ausgabe von vgdisplay; entscheidend ist die Zeilen mit "Total PE" (zumindest sofern man, wie ich, nur eine LV in der VG definiert hat). Hat man sich dafür entschieden, wie viele PEs die LV nun aufbrauchen darf, erledigt lvresize das innerhalb eines Lidschlags:

# lvresize -l 1430000 /dev/myVG/myLV

Ich persönlich habe es mir zur Gewohnheit gemacht, die Anzahl der PEs immer auf ganze Tausenderstellen abzurunden. Auf diese verliert man maximal knapp unter 4000MiB Nettokapazität (bei der Default-PE-Größe von 4MiB), hat im Zweifelsfall aber ein bisschen mehr Luft für Snapshots oder auch temporäre Volumes, die man - das lehrt die Erfahrung - öfter braucht als man meinen möchte.

Zu guter letzt bleibt noch das Vergrößern des Dateisystems - in meinem Fall ext4. Dies erledigt das Programm resize2fs, und das recht gemächlich. Der Name rührt noch vom Urahn von ext4, dem Second Extended FS (ext2) her, und kann alle Versionen der ext-Dateisysteme vergrößern und auch verkleinern. Der Aufruf ist reichlich unspektakulär:

# resize2fs /dev/myVG/myLV

Abermals gilt: Fordert man nicht explizit weniger an, wird das Dateisystem auf den maximal zur Verfügung stellbaren Platz aufgepumpt. Man kann dem Dateisystem während des Wachsens zusehen, um den Fortschritt der Operation im Überblick zu behalten - wiederholtes Aufrufen von df verlangsamt den Prozess nicht merklich, und liefert unkompliziert Feedback und die Gewissheit, dass alles in Ordnung ist. Wer Zeit sparen, auf Nummer sicher gehen und eine Downtime verkraften will und kann, kann das Dateisystem vor dem Vergrößern unmounten - nötig ist das aber nicht.

Ein angemessenes Wort der Warnung noch zum Schluss: Alle Daten, von denen kein Backup existiert, sind als gelöscht zu betrachten!

direkter Link ▲

© 2007-2019 Johannes Truschnigg | valid xhmtl & css