dRAID steht für distributed Spare RAID und ist eine Implementation für ZFS. Ein dRAID vdev ist zusammengesetzt aus RAIDZ Array Gruppen und wird in Proxmox VE ab der Version 7.3 unterstützt. Die Besonderheit von dRAID sind die inbegriffenen verteilten Hot Spares.
Dieser Artikel gibt einen Überblick über die Funktionsweise von dRAID und zeigt die Einrichtung eines vdev auf Basis von dRAID unter Proxmox 7.3.
dRAID hat das Ziel, sowohl parity als auch spare auf alle Datenträger im Verbund zu verteilen. Die besonderen Merkmale eines solchen Verbunds sollen im Folgenden erläutert werden.
Ein dRAID-Verbund besteht aus
Diese werden in sogenannten slices angeordnet (s.u.). Die RAIDZ Gruppen werden dabei in der Definition des dRAID festgelegt - ein dRAID1 nutzt RAIDZ-1 Gruppen, ein dRAID3 verwendet RAIDZ-3 Gruppen.
Bei der Definition eines dRAID müssen also immer die Parameter data, parity und spare festgelegt werden. Optional kann auch die Gesamtzahl der eingebundenen Datenträger (im dRAID children genannt) angegeben werden.
Möglich sind - analog den RAIDZ Leveln - 1, 2 oder 3 parity. Die Anzahl der spares kann frei bestimmt werden, wobei der Standardwert 0 ist. Die Datenanteile sind frei wählbar bis zu einem Maximum. Dieses wird bestimmt durch die Gesamtzahl der children abzüglich der gewünschten parities und spares im Verbund.
Hier einige Beispiele möglicher Definitionen:
Datenträger (children) | Definition | parity | data | spares |
---|---|---|---|---|
4 | dRAID:2d:1s:4c | 1 | 2 | 1 |
11 | dRAID2:7d:2s:11c | 2 | 7 | 2 |
26 | dRAID3:8d:2s:26c | 3 | 8 | 2 |
50 | dRAID2:7d:3s:50c | 2 | 7 | 3 |
Im Gegensatz zu einem herkömmlichen RAIDZ ist die Stripe-Länge bei einem dRAID festgelegt. Die Stripe-Width ergibt sich aus der Disk Sector Size multipliziert mit den data-Anteilen.
Beispiel: Eine Disk Sector Size von 4k und ein Daten-Anteil von 7 (siehe Beispiel 2 oben) ergäbe eine Stripe-Width von 7 * 4k = 28k.
Ein dRAID Verbund ist ein Zusammenspiel verschiedener Teile[1]:
child | Bezeichnet einen Datenträger innerhalb eines dRAID Verbunds. |
row | Ein 16 MB großer Chunk, der auf allen Datenträger denselben Offset hat. |
group | Bezeichnet die RAIDZ-Gruppen innerhalb des dRAID. Sie beinhalten Daten und Parität. Falls notwendig, können groups row-übergreifend verteilt werden. |
slice | Ein slice bildet den Rahmen für groups und rows innerhalb eines dRAID Verbunds. Er ist abgeschlossen, sobald die groups einer row vollständig beschrieben sind. |
device map | Die device map bestimmt die Verteilung von data, parity und spare auf die children im Verbund. Sie ist in Reihen bzw. columns eingeteilt. |
Die device map wird für jeden slice neu festgelegt wird. Daher ist es sinnvoll sich den Aufbau eines slices zu verdeutlichen:
Jede Reihe innerhalb der device map steht für ein child im dRAID. In jedem slice wird sie zufällig permutiert, also neu angeordnet. Das sorgt dafür, dass data, parity und spares zufällig auf alle children verteilt werden. Dadurch werden Hot-Spots innerhalb des RAID Sets vermieden. Die spare-Anteile sind innerhalb eines slices statisch. Sie werden über die einzelnen slices verteilt.
Betrachtet man zusätzlich auch groups und rows, ergibt sich ein vollständiges Bild eines dRAID.
Betrachten wir das Beispiel eines dRAID2:4d:2s:11c. Diese Definition bedeutet, der Verbund wird gebildet aus 11 children. Jede group beinhaltet 4 data und 2 parity, was einem RAIDZ-2 entspricht. Zustätzlich sollen 2 spares gebildet werden. Da 11 children zur Verfügung stehen, aber mit data, parity und spares nur 9 children genutzt werden, müssen in diesem dRAID-Verbund groups auf mehrere rows verteilt werden. Am besten verdeutlicht man sich dies anhand eines Diagramms:
Solange also die Summe der data, parity und spares unter der Anzahl der children liegt, kann man immer ein dRAID bilden.
Die Anzahl der groups innerhalb eines slice hängt dabei davon ab, wann eine row vollständig und ohne Rest abgeschlossen wird. Die notwendigen groups innerhalb eines Verbunds können mithilfe einer kurzen Berechnung ermittelt werden.
Die columns einer group bestimmen sich aus der Summe aus data und parity. Aus der Differenz von children und spares ergibt sich, wieviele columns insgesamt von groups gefüllt werden müssen. Das kleinste gemeinsame Vielfache dieser beiden Werte zeigt dann, wie viele groups benötigt werden, bis eine row vollständig und ohne Rest befüllt werden kann:
n := groups pro slice, d :=data, p := parity, c := children, s := spare n * d+p = KgV(d+p,c-s)
In unserem Beispiel ergibt das:
n * d+p = KgV(d+p,c-s) n * 6 = KgV(6,9) n * 6 = 18 n = 3
Es werden also 3 groups benötigt.
In der folgenden Tabelle wird dRAID verglichen mit anderen RAID-Arten. Dabei ist zu beachten, dass die diagrammatische Darstellung des dRAID stark vereinfacht ist und die device map nicht berücksichtigt wird.
Dieser Abschnitt befasst sich mit der Einrichtung eines dRAID. Sie funktioniert für alle Distributionen, die mindestens OpenZFS 2.1.0 bereitstellen.
Es ist sinnvoll ein dRAID über die SCSI-IDs anzulegen, was einen späteren Austausch von Datenträgern erleichtert. Eine Einrichtung mit SCSI-IDs ist per GUI einfacher, über das Terminal ist sie aber ebenfalls möglich.
Die Einrichtung über das Terminal ist sehr einfach und benötigt nur einen Befehl.
Die Einrichtung gelingt mit[2]
# zpool create <options> <pool> draid[<parity>][:<data>d][:<children>c][:<spares>s] <vdevs...>
Zur Erläuterung:
Befehl | Beschreibung |
---|---|
zpool | Paket zur Erstellung eines ZFS Storage Pools. |
create | Befehl zur Erstellung eines zpool. |
<options> | Hier können die regulären Optionen für einen zpool gesetzt werden. |
<pool> | Feld für den Namen des zu erstellenden zpool. |
draid[<parity>] | Befehl zur Definition des dRAID. Mögliche Paritäten sind 1 (Default), 2 und 3. |
[:<data>d] | Anzahl der Daten-Devices pro Gruppe. Ein niedrigerer Wert erhöht IOPS, Kompressionsrate und verbessert die Resilvering-Dauer. Verringert gleichzeitig auch die nutzbare Datenkapazität (Default 8). |
[:<children>c] | Gesamtzahl der zu verwendenden Datenträger. |
[:<spares>s] | Anzahl der Spare-Devices (Default 0). |
<vdevs...> | Eingabe der im dRAID zu verwendenden vdevs. |
Hinweis: [:d][:c][:s] können in beliebiger Reihenfolge verwendet werden.
Hier eine Beispielhafte Konfiguration:
Ein dRAID ist ein regulärer zpool und wird wie gewohnt eingerichtet:
Kompression und ashift[3] bestimmen, Data-Devices und Spares wählen. Dann bestätigen.
Der Unterschied bei der (einfachen) Einrichtung per Terminal bzw. GUI ist hier zu sehen:
Dieser Abschnitt beschreibt das Resilvering und das Rebalancing eines dRAID im Falle eines Defekts innerhalb des Verbunds.
Durch die im Verbund enthaltenen Spare-Anteile funktioniert das Resilvering im dRAID automatisch sobald der ZFS Event Daemon (ZED)[4] den Ausfall bemerkt. Die folgende Bildreihe verdeutlicht den Vorgang innerhalb der Proxmox-Umgebung:
dRAID unterstützt sowohl sequential resilver[5] als auch traditionelles healing resilver.
Der Vorteil von sequential resilver bei dristibuted Hot-Spares ist, dass die Rebuild-Zeit mit dem Quotienten aus disks und Stripe-Länge skaliert[6].
Standardmäßig ist sequential resilver aktiviert. Dies kann mit dem Befehl
# zpool get feature@device_rebuild
abgefragt werden[7]. In unserem Fall erhalten wir folgende Ausgabe:
# zpool get feature@device_rebuild NAME PROPERTY VALUE SOURCE rpool feature@device_rebuild enabled local tank feature@device_rebuild enabled local
Dieser Wert muss bei der Erstellung des Verbunds gesetzt werden. Eine nachträgliche Änderung ist nicht möglich:
# zpool set feature@device_rebuild=disabled tank cannot set property for 'tank': property 'feature@device_rebuild' can only be set to 'disabled' at creation time
Der richtige Befehl zur Erstellung eines dRAID ohne sequential resilver ist:
# zpool create -o feature@device_rebuild=disabled <pool> ...
Beispiel:
root@pve73-test:~# zpool create -o feature@device_rebuild=disabled tank draid:2d:2s:5c /dev/sd[d-h] root@pve73-test:~# zpool get feature@device_rebuild NAME PROPERTY VALUE SOURCE rpool feature@device_rebuild enabled local tank feature@device_rebuild disabled local root@pve73-test:~#
Dieser Vorgang beschreibt den Ausgleich eines RAID-Verbundes durch ersetzen eines ausgefallenen Datenträgers. Wird ein Hard-Drive mit derselben SCSI-ID in das System eingebunden, so findet ein Rebalance automatisch statt. Soll ein Datenträger mit einer anderen SCSI-ID eingebunden werden, so ist dies in der aktuellen Proxmox Version 7.3-3 nicht per GUI, sondern ausschließlich über das Terminal möglich.
Der Befehl für das Einbinden eines neuen Laufwerks in den Verbund ist:
# zpool replace <pool> <device-old> <device-new>
In der folgenden Bilderreihe wird der Vorgang verdeutlicht:
Autor: Stefan Bohn Stefan Bohn ist seit 2020 bei der Thomas-Krenn.AG beschäftigt. Ursprünglich als Berater für IT-Lösungen im PreSales beheimatet, wechselte er 2022 zum Product Management. Dort widmet er sich dem Wissenstransfer und treibt dabei auch das Thomas-Krenn Wiki voran. |