To main content

Zwei Festplatten in einem btrfs raid1 zusammenführen

Veröffentlicht von Benjamin Marwell am
Ein btrfs raid1 ist eine Datenspiegelung auf Dateisystemebene. Wer schonmal Daten mit btrfs verloren hat, kennt die unangenehmen Meldungen beim btrfs scrub.
scrub status for <UUID>
  scrub started at Thu Dec 25 15:19:22 2014 and was aborted after 89882 seconds
  total bytes scrubbed: 1.87TiB with 4 errors
  error details: csum=4
  corrected errors: 0, uncorrectable errors: 4, unverified errors: 0
Wer noch Platz auf einer anderen Festplatte übrig hat, kann über einen btrfs raid1 auf Dateisystemebene diese Probleme umgehen. Der folgende Artikel beschreibt den Migrationsweg.

Warum btrfs statt mdadm für raid1 verwenden?

Nun, dafür gibt es einige Vorteile. Zum einen ist eine Prüfung auf Dateisystemebene einfacher, weil Metadaten und Daten gespiegelt werden. Die Prüfung ist zwar CPU-Intensiver, aber so lässt sich auch feststellen, welche der beiden Kopien in Ordnung ist. Zudem werden btrfs-Dateisysteme bei initrd-Support automatisch erkannt, beide Partitionen werden dann zu einem btrfs-Volumen quasi konfigurationsfrei zusammengefügt. Außerdem ist die Umsetzung recht einfach. Nachteile sind etwa: Hoher CPU-Verbrauch während der Prüfung und das manuelle Anlegen von Prüfjobs (btrfs scrub ).

Festplatte bzw. btrfs-Partition für raid1 vorbereiten

Für ein btrfs raid1 sollten die beiden Ziel-Partitionen auf beiden Geräten gleich groß sein. Es muss also der kleinste gemeinsame Nenner gefunden werden. Das geht am einfachsten über die Anzahl der Sektoren über fdisk:
[server] [~]  # fdisk -l /dev/sdb
Disk /dev/sdb: 698.7 GiB, 750156374016 bytes, 1465149168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x000325ff

Device     Boot Start        End    Sectors   Size Id Type
/dev/sdb2        2048 1465147391 1465145344 698.7G 83 Linux
In Zeile 10 sieht man die Anzahl an Sektoren. Dieses ist die wichtige Zielgröße. Wir nutzen diese nun für die neue Partition /dev/sdc1  (in meinem Fall). Mit dem Befehl sudo cfdisk /dev/sdc  lässt sich über eine schöne GUI die neue Partition erstellen. Als Größe habe ich entsprechend 1465145344S eingegeben. Wichtig ist das S am Ende! Ein Formatieren der zweiten Partition mittels mkfs.btrfs  ist nun nicht notwenig. Allenfalls kann man mittels sudo partprobe  die Partitionstabellen neu einlesen.

Partitionen mounten

Nun mounted man die Partitionen, angefangen mit dem existierenden Dateisystem.
sudo mount /dev/sdb2 /media/nextcloud
Als nächstes fügt man die neue Partition hinzu. Btrfs kennt dazu den folgenden Befehl:
btrfs device add /dev/sdc1 /media/nextcloud

Das btrfs raid1 erstellen

Aber Achtung! Wir sind nun noch nicht fertig! Derzeit hätten wir ein JBOD (»Just a bunch of disks«), also ein großes Dateisystem von (hier) ca. 1200 GiB. Die Konversion in ein Raid1 funktioniert gut und ohne Datenverlust mittels zweier Befehle. Übrigens: Man kann auch beide Befehle kombinieren, aber das ist interessanterweise weniger performant.

Metadaten auf Raid1 konvertieren

Im ersten Schritt werden die Metadaten als raid1 geklont, im zweiten Schritt die echten Daten.
btrfs fi balance start -mconvert=raid1,soft  /media/nextcloud/
Erklärung:
  • fi balance  (kurz für filesystem balance ) ist ein Befehl, der die Daten über ein Profil neu anordnen lässt.
  • -m  ist die Option, um mit Metadaten zu arbeiten.
  • -mconvert  ist entsprechend die Option, ein neues Profil auf die Metadaten des Diskarrays anzuwenden.
  • raid1,soft  ist das Profil btrfs raid1. soft  sorgt dafür, dass es sich nur auf Daten auswirkt, die noch nicht diesem Profil entsprechen. Bei der ersten Ausführung sind das alle Daten.

Nutzdaten auf raid1 konvertieren

Um auch die Nutzdaten zu spiegeln, verwendet man analog folgenden Befehl:
btrfs fi balance start -dconvert=raid1,soft  /media/nextcloud/
Dabei steht -dconvert=  entsprechend für ein neues Profil auf die Nutzdaten des Diskarrays zu legen. Dieser Befehl dauert etwas länger. In einer zweiten Shell kann man auch mit folgendem Befehl zugucken:
btrfs filesystem balance status /media/nextcloud

Finaler Test

Festplattennutzung und single chunks

Nach dem Erstellen des neuen Profils auf dem btrfs raid1 Dateisystem könnten trotzdem noch einzelne Chunks nur auf einer physischen Festplatte liegen. Diese sind aber in der Regel null Bytes groß, da ja alle tatsächlichen Daten konvertiert wurden. Zu erkennen ist das wie folgt:
btrfs fi usage /mnt/btrfs
…
Data,single: Size: ~ GiB, Used: ~GiB
   /dev/sdc1   1.00GiB
…
Diese leeren (aber dennoch Speicher reservierenden) chunks lassen sich auch schnell vom btrfs raid1 entfernen.
btrfs balance start -dusage=0 -musage=0 /mnt/btrfs
Der obrige Befehl führt ein Balancing auf Chunks aus, die keinen Platz belegen.

Mount-Optionen

Ein Mount der btrfs-Devices funktioniert automatisch, sobald man eines der devices mountet. Wer aber ganz sicher gehen möchte oder wessen initrd kein btrfs detect  ausführt, kann alle devices in der Datei /etc/fstab  per Hand eingeben. Ich verwende hier zum Teil Devicenamen, besser wären aber UUIDs.
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>

# …

# /dev/sdb2 (nextcloud)
UUID=4466888b-629a-439e-9f91-809b7f5fd309   /media/nextcloud      btrfs   device=/dev/sdb2,device=/dev/sdb2,defaults,rw,user,nofail         0   2
Die UUIDs findet man wie folgt heraus (sind aber optional):
ls -lF /dev/disk/by-uuid/ | grep sd[bc]

Prüfen des Devices

Wer ganz sicher gehen will, der kann schauen, ob beide Devices (und die Partitionen auf diesen) wirklich dem neuen btrfs raid1 volume zugeordnet sind:
[server] [~]  # btrfs fi show /media/nextcloud/
Label: 'Externe Festplatten RAID1'  uuid: 4466888b-629a-439e-9f91-809b7f5fd309
	Total devices 2 FS bytes used 120.10GiB
	devid    1 size 698.64GiB used 123.03GiB path /dev/sdb2
	devid    2 size 698.64GiB used 123.03GiB path /dev/sdc1
Hier ist etwa zu erkennen, dass zwei Devices (bzw. Partitionen) genutzt werden, die jeweis knapp 700 GiB groß sind. Es sind ca. 120 GiB Nutzdaten darauf, die aber zusammen mit Metadaten etc. auf jeder physischen Partition 123 GiB belegen. Die genaue Belegung lässt sich mit folgendem Befehl anzeigen:
[server] [~]  # btrfs fi usage /media/nextcloud/
Overall:
    Device size:		   1.36TiB
    Device allocated:		 246.06GiB
    Device unallocated:		   1.12TiB
    Device missing:		     0.00B
    Used:			 240.21GiB
    Free (estimated):		 577.68GiB	(min: 577.68GiB)
    Data ratio:			      2.00
    Metadata ratio:		      2.00
    Global reserve:		  64.00MiB	(used: 0.00B)

Data,RAID1: Size:122.00GiB, Used:119.92GiB
   /dev/sdb2	 122.00GiB
   /dev/sdc1	 122.00GiB

Metadata,RAID1: Size:1.00GiB, Used:189.17MiB
   /dev/sdb2	   1.00GiB
   /dev/sdc1	   1.00GiB

System,RAID1: Size:32.00MiB, Used:48.00KiB
   /dev/sdb2	  32.00MiB
   /dev/sdc1	  32.00MiB

Unallocated:
   /dev/sdb2	 575.60GiB
   /dev/sdc1	 575.60GiB
Wie zu sehen, findet man die Werte hier wieder, allerdings die 123 GiB aufgeteilt auf Data, Metadata und System.

Wartung mittels btrfs scrub

Nun aber zum wichtigsten Vorteil: btrfs scrub .  Sollten mal Daten nicht korrekt sein, muss das btrfs ja auch irgendwie merken. Dieses geschried mittels btrfs scrub , welches selbstverständlich auch auf einem btrfs raid1 korrekt arbeitet und dabei Fehlerhafte (Meta-)daten erkennt und von der noch heilen Partition restauriert. Den Befehl kann man mittels cron oder systemd-Timer laufen lassen. Ich habe mich hier für systemd-Timer entschieden - einen wirklichen Grund zu dieser Lösung gegenüber cron hatte ich aber nicht.

systemd-Unit und Timer installieren

Die Sourcen findet man hier in diesem Gist auf github: https://gist.github.com/gbrks/11b9d68d19394a265d70. Allerdings muss eine Datei verändert werden, dazu mehr. Die Dateien legt man wie folgt ab:
  • /usr/local/bin/btrfs-scrub
  • /etc/systemd/system/btrfs-scrub.service
  • /etc/systemd/system/btrfs-scrub.timer
In der Service-Datei nutzt man noch den Type=oneshot  statt Type=simple, da der Prozess sich nach getaner Arbeit beendet. Zur Anpassung der Erinnerungs-E-Mail bitte weiter unten lesen.

Aktivierung der systemd-Services

Den Service und den Timer muss man nun in systemd nachladen und aktivieren. Das geschieht mittels folgender Befehle.
sudo systemctl daemon-reload
sudo systemctl enable btrfs-scrub.service
sudo systemctl enable btrfs-scrub.timer
sudo systemctl start btrfs-scrub.timer
Der erste Befehl lässt systemd die Konfigurationsdateien neu einladen. Danach werden der Service (der keine Startanforderung besitzt), sowie der Timer aktiviert. Nun muss man den Timer einmalig starten.

Anpassen der E-Mail-Benachrichtigung

Die E-Mailbenachrichtigung kann man anpassen. Ich habe mich dafür entschieden, nicht (wie in der Vorlage) Mailgun zu verwenden, sondern meinen Gmail-Account. Zunächst legt man die Datei /root/.netrc wie folgt an:
machine smtp.google.com
login user@gmail.com
password myapppw
Wenn man nicht sein Standard-Passwort nutzen möchte (sollte man auch nicht!), so kann man hier ein App-Passwort erstellen. Das ist bei 2-Stufiger Authentifizierung sogar zwingend notwendig. Als nächstes ersetzt man das obrige Gist durch die Änderungen, die ich in meinem Fork dokumentiert habe.

Fehlerkorrekturen per Mail

Werden Fehler in dem btrfs raid1 volume gefunden und korrigiert, so sieht de Mail dann aus wie bei Oracle beschrieben.
$ btrfs scrub status /btrfs
scrub status for 15e213ad-4e2a-44f6-85d8-86d13e94099f
scrub started at Wed Sep 28 12:36:26 2011 and finished after 2 seconds
     total bytes scrubbed: 200.48MB with 13 errors
     error details: csum=13
     corrected errors: 13, uncorrectable errors: 0, unverified

$ dmesg | tail
btrfs: fixed up at 1103101952
btrfs: fixed up at 1103106048
btrfs: fixed up at 1103110144
btrfs: fixed up at 1103114240
btrfs: fixed up at 1103118336
btrfs: fixed up at 1103122432
btrfs: fixed up at 1103126528
btrfs: fixed up at 1103130624
btrfs: fixed up at 1103134720
btrfs: fixed up at 1103138816
Wie man nun sieht, hat man nun endlich korrigierbare Fehler.

Fazit

Mit btrfs hat man auf Dateisystemebene eine leichtgewichtige raid1-Implementierung, die relativ zügig umgesetzt ist. Nachteile sind unter anderem die manuellen Wartungsskripte und teilweise hohe CPU-Last beim Scrub auf dem btrfs raid1.