
In diesem FrĂŒhling haben wir bereits einige EinfĂŒhrungsthemen besprochen, wie zum Beispiel und . In dem zweiten Artikel haben wir sogar versprochen, die Leistung verschiedener Multi-Disk-Topologien in ZFS weiter zu untersuchen. Dies ist ein Next-Generation-Dateisystem, das derzeit ĂŒberall implementiert wird: von bis zu .
Nun, heute ist der perfekte Tag, um ZFS kennenzulernen, neugierige Leser. Seien Sie sich nur bewusst, dass, laut SchĂ€tzung des Entwicklers von OpenZFS, Matt Arens, âes wirklich komplex istâ.
Aber bevor wir zu den Zahlen kommen â und die werden kommen, das verspreche ich â mĂŒssen wir ĂŒber das sprechen, als wie ZFS Daten auf dem Laufwerk speichert.
Zpool, vdev und device

Dieses Diagramm des gesamten Pools umfasst drei Hilfs-vdevs, jeweils eines jeder Klasse, und vier fĂŒr RAIDz2

Normalerweise gibt es keinen Grund, einen Pool aus unterschiedlichen Typen und GröĂen von vdev zu erstellen â aber wenn Sie möchten, steht Ihnen nichts im Wege.
Um das Dateisystem ZFS wirklich zu verstehen, ist es wichtig, seine tatsĂ€chliche Struktur genauer zu betrachten. ZunĂ€chst einmal vereint ZFS traditionelle Ebenen der Volumenverwaltung und des Dateisystems. AuĂerdem verwendet es einen transaktionalen Mechanismus zum Copy-on-Write. Diese Merkmale bedeuten, dass sich das System strukturell erheblich von herkömmlichen Dateisystemen und RAID-Arrays unterscheidet. Die ersten grundlegenden Bausteine fĂŒr das VerstĂ€ndnis sind: der Storage-Pool (zpool), das virtuelle GerĂ€t (vdev) und das physische GerĂ€t (device).
zpool
Der Storage-Pool zpool ist die oberste Struktur von ZFS. Jeder Pool enthÀlt ein oder mehrere virtuelle GerÀte. Diese wiederum enthalten ein oder mehrere physische GerÀte (device). Virtuelle Pools sind eigenstÀndige Einheiten. Ein physischer Computer kann zwei oder mehr separate Pools enthalten, die jedoch vollstÀndig unabhÀngig voneinander sind. Pools können keine virtuellen GerÀte gemeinsam nutzen.
Die Redundanz von ZFS erfolgt auf der Ebene der virtuellen GerĂ€te und nicht auf der Ebene der Pools. Auf der Pool-Ebene gibt es keinerlei Redundanz â wenn ein vdev-SpeichergerĂ€t oder ein spezielles vdev verloren geht, geht der gesamte Pool ebenfalls verloren.
Moderne Storage-Pools können den Verlust des Caches oder des Journals eines virtuellen GerĂ€ts ĂŒberstehen â sie können jedoch eine kleine Menge an nicht gespeicherten Daten verlieren, wenn sie das vdev-Journal wĂ€hrend eines Stromausfalls oder Systemausfalls verlieren.
Ein weit verbreitetes MissverstĂ€ndnis ist, dass die 'Datenstreifen' (Striping) von ZFS ĂŒber den gesamten Pool verteilt werden. Das ist falsch. Zpool ist keineswegs ein unterhaltsamer RAID0, es ist eher ein unterhaltsames mit einem komplexen, variablen Verteilungsmechanismus.
Im Wesentlichen werden die SchreibvorgĂ€nge gleichmĂ€Ăig auf die verfĂŒgbaren virtuellen GerĂ€te verteilt, basierend auf dem verfĂŒgbaren Speicherplatz. Theoretisch werden alle gleichzeitig belegt. In neueren Versionen von ZFS wird die aktuelle Auslastung (Utilisation) der vdev berĂŒcksichtigt â falls ein virtuelles GerĂ€t wesentlich stĂ€rker belastet ist als ein anderes (z. B. aufgrund von LesevorgĂ€ngen), wird es vorĂŒbergehend fĂŒr SchreibvorgĂ€nge ĂŒbersprungen, selbst wenn es den höchsten freien Speicherplatz aufweist.
Der in moderne ZFS-Schreibstrategien integrierte Mechanismus zur Ermittlung der Auslastung kann die Latenz verringern und die Durchsatzrate wĂ€hrend Zeiten ungewöhnlich hoher Belastung erhöhen â jedoch ist das nicht. Blankoscheck fĂŒr das unbeabsichtigte Mischen von langsamen HDDs und schnellen SSDs in einem Pool. Ein solch unausgewogener Pool wird stets mit der Geschwindigkeit des langsamsten GerĂ€ts arbeiten, als ob er vollstĂ€ndig aus diesen GerĂ€ten zusammengesetzt wĂ€re.
vdev
Jeder Speicherpool besteht aus einem oder mehreren virtuellen GerĂ€ten (virtual device, vdev). Jedes vdev umfasst wiederum eines oder mehrere physische GerĂ€te. Die meisten virtuellen GerĂ€te dienen der einfachen Datenspeicherung, aber es gibt mehrere unterstĂŒtzende vdev-Klassen, einschlieĂlich CACHE, LOG und SPECIAL. Jeder dieser vdev-Typen kann eine von fĂŒnf Topologien aufweisen: EinzelgerĂ€t (single-device), RAIDz1, RAIDz2, RAIDz3 oder Spiegelung (mirror).
RAIDz1, RAIDz2 und RAIDz3 sind spezielle Varianten dessen, was man frĂŒher als RAID mit doppelter (diagonaler) ParitĂ€t bezeichnete. 1, 2 und 3 beziehen sich darauf, wie viele ParitĂ€tsblöcke fĂŒr jedes Datenband bereitgestellt werden. Anstelle von einzelnen Festplatten zur Bereitstellung der ParitĂ€t verteilen die virtuellen RAIDz-GerĂ€te diese ParitĂ€t gleichmĂ€Ăig ĂŒber die Festplatten. Ein RAIDz-Array kann so viele Festplatten verlieren, wie es ParitĂ€tsblöcke gibt; wenn eine weitere ausfĂ€llt, wird es inkompatibel und nimmt den Speicherpool mit sich.
In spiegelnden virtuellen GerĂ€ten (mirror vdev) wird jeder Block auf jedem GerĂ€t im vdev gespeichert. WĂ€hrend die am hĂ€ufigsten verwendeten Doppelspiegel (two-wide) sind, kann in einem Spiegel eine beliebige Anzahl von GerĂ€ten vorhanden sein â in gröĂeren Installationen werden hĂ€ufig dreifache Spiegel verwendet, um die Leseleistung und die Ausfallsicherheit zu erhöhen. Ein vdev-Spiegel kann jeden Ausfall ĂŒberstehen, solange mindestens ein GerĂ€t im vdev weiter funktioniert.
Einzelne vdevs sind von Natur aus gefĂ€hrlich. Ein solches virtuelles GerĂ€t ĂŒbersteht keinen einzigen Ausfall â und wenn es als Speicher oder als spezieller vdev verwendet wird, fĂŒhrt sein Ausfall zur Zerstörung des gesamten Pools. Seien Sie hier Ă€uĂerst vorsichtig.
Virtuelle GerĂ€te wie CACHE, LOG und SPECIAL können in jeder der oben genannten Topologien erstellt werden â aber bedenken Sie, dass der Verlust eines virtuellen GerĂ€ts SPECIAL den Verlust des gesamten Pools bedeutet, daher wird eine redundante Topologie dringend empfohlen.
device
Wahrscheinlich ist dies der einfachste Begriff in ZFS â es ist buchstĂ€blich ein BlockgerĂ€tespeicher. Denken Sie daran, dass virtuelle GerĂ€te aus einzelnen GerĂ€ten bestehen und ein Pool aus virtuellen GerĂ€ten besteht.
Festplatten â egal ob magnetisch oder flashbasierend â sind die am hĂ€ufigsten verwendeten BlockgerĂ€te, die als Bausteine fĂŒr vdev dienen. Aber jedes GerĂ€t mit einem Deskriptor in /dev passt â sodass auch ganze hardwarebasierte RAID-Systeme als einzelne GerĂ€te verwendet werden können.
Eine einfache Raw-Datei ist eines der wichtigsten alternativen BlockgerĂ€te, aus denen ein vdev aufgebaut werden kann. Testpools aus  sind eine sehr praktische Möglichkeit, um Befehle des Pools zu testen und zu sehen, wie viel Speicher im Pool oder im virtuellen GerĂ€t dieser Topologie verfĂŒgbar ist.

Sie können innerhalb von Sekunden einen Testpool aus Sparse-Dateien erstellen â aber vergessen Sie nicht, den gesamten Pool und seine Komponenten anschlieĂend zu löschen.
Angenommen, Sie möchten einen Server mit acht Festplatten einrichten und planen, 10 TB (~9300 GiB) groĂe Festplatten zu verwenden, sind sich jedoch nicht sicher, welche Topologie am besten zu Ihren Anforderungen passt. In dem obigen Beispiel erstellen wir in nur wenigen Sekunden einen Testpool aus dĂŒnn provisionierten Dateien â und jetzt wissen wir, dass ein RAIDz2 vdev aus acht Festplatten mit 10 TB eine nutzbare KapazitĂ€t von 50 TiB bietet.
Eine weitere spezielle GerĂ€teklasse sind SPARE (ErsatzgerĂ€te). Hot-Swap-GerĂ€te gehören, im Gegensatz zu normalen GerĂ€ten, dem gesamten Pool an und nicht einem einzelnen virtuellen GerĂ€t. Wenn ein vdev im Pool ausfĂ€llt und ein ErsatzgerĂ€t mit dem Pool verbunden und verfĂŒgbar ist, wird es automatisch mit dem betroffenen vdev verbunden.
Nachdem das ErsatzgerĂ€t mit dem betroffenen vdev verbunden ist, beginnt es, Kopien oder Rekonstruktionen der Daten zu empfangen, die auf dem fehlenden GerĂ€t sein sollten. Dies wird in traditionellem RAID als Wiederherstellung (rebuilding) bezeichnet, wĂ€hrend es in ZFS als âWiederherstellung von Redundanzâ (resilvering) bekannt ist.
Es ist wichtig zu beachten, dass ErsatzgerĂ€te nicht dauerhaft defekte GerĂ€te ersetzen. Sie dienen nur als vorĂŒbergehende Lösung, um die Zeit zu verkĂŒrzen, in der eine vdev-Abwertung stattfindet. Nachdem der Administrator das defekte vdev-GerĂ€t ersetzt hat, wird die Redundanz wieder auf das permanente GerĂ€t hergestellt, wĂ€hrend das SPARE von der vdev getrennt und wieder als Reserve im gesamten Pool verwendet wird.
DatensÀtze, Blöcke und Sektoren
Der nĂ€chste Block in unserer Erkundung von ZFS betrifft nicht so sehr die Hardware, sondern wie die Daten selbst organisiert und gespeichert werden. Hier ĂŒberspringen wir einige Ebenen â wie den Metaslab â um Ăberladungen zu vermeiden und den Ăberblick ĂŒber die Gesamtstruktur zu behalten.
Datensatz (dataset)

Wenn wir einen Datensatz erstellen, zeigt dieser den gesamten verfĂŒgbaren Speicherplatz im Pool an. Dann setzen wir ein Quota und Ă€ndern den EinhĂ€ngepunkt. VoilĂ !

Zvol ist im Wesentlichen ein Datensatz ohne seine Dateisystemschicht, die wir hier durch ein ganz normales Dateisystem wie ext4 ersetzen.
Ein ZFS-Datensatz ist in etwa mit einem standardmĂ€Ăigen gemounteten Dateisystem vergleichbar. Wie bei einem gewöhnlichen Dateisystem scheint er auf den ersten Blick âeinfach nur ein weiterer Ordnerâ zu sein. Aber auch wie bei herkömmlichen gemounteten Dateisystemen hat jeder ZFS-Datensatz seine eigenen grundlegenden Eigenschaften.
ZunÀchst kann einem Datensatz ein festgelegtes Kontingent zugewiesen werden. Wenn Sie zfs set quota=100G poolname/datasetnamefestlegen, können Sie nicht mehr als /poolname/datasetname 100 GiB in den gemounteten Ordner schreiben.
Haben Sie die PrĂ€senz â und Abwesenheit â von SchrĂ€gstrichen am Anfang jeder Zeile bemerkt? Jeder Datensatz hat seinen eigenen Platz sowohl in der ZFS-Hierarchie als auch in der Hierarchie des System-Managements. In der ZFS-Hierarchie gibt es keinen fĂŒhrenden SchrĂ€gstrich â Sie beginnen mit dem Poolnamen und dann dem Pfad von einem Datensatz zum nĂ€chsten. Zum Beispiel: pool/parent/child fĂŒr einen Datensatz mit dem Namen child unter dem ĂŒbergeordneten Datensatz parent in einem Pool mit dem kreativen Namen pool.
StandardmĂ€Ăig entspricht der Mount-Punkt eines Datensatzes seinem Namen in der ZFS-Hierarchie, beginnend mit einem SchrĂ€gstrich â der Pool mit dem Namen pool wird als /poolgemountet, der Datensatz parent wird in /pool/parentgemountet und der untergeordnete Datensatz child wird in /pool/parent/child. Aber der System-Mountpunkt des Datensatzes kann geĂ€ndert werden.
Wenn wir angeben, zfs set mountpoint=/lol pool/parent/child, dann wird der Datensatz pool/parent/child im System als /lol.
ZusĂ€tzlich zu DatensĂ€tzen sollten wir Volumes (zvols) erwĂ€hnen. Ein Volume ist ungefĂ€hr vergleichbar mit einem Datensatz, wobei es jedoch tatsĂ€chlich kein Dateisystem hat â es handelt sich einfach um ein BlockgerĂ€t. Sie können beispielsweise ein zvol mit dem Namen mypool/myzvol, erstellen, es dann mit einem ext4-Dateisystem formatieren und dieses Dateisystem dann einhĂ€ngen â jetzt haben Sie ein ext4-Dateisystem, jedoch mit UnterstĂŒtzung fĂŒr alle Sicherheitsfunktionen von ZFS! Das mag auf einem Computer seltsam erscheinen, macht jedoch viel mehr Sinn als Backend bei der Exportierung eines iSCSI-GerĂ€ts.
Blöcke

Eine Datei wird durch einen oder mehrere Blöcke dargestellt. Jeder Block wird auf einem virtuellen GerĂ€t gespeichert. Die BlockgröĂe entspricht normalerweise dem Parameter recordsize, kann jedoch auf 2^ashiftverringert werden, wenn er Metadaten oder eine kleine Datei enthĂ€lt.

Wir meinen es wirklich ernst, gibt es wirklich wenn wir vom enormen Leistungsdefizit sprechen, das entsteht, wenn der ashift zu klein eingestellt wird.
Im ZFS-Pool werden alle Daten, einschlieĂlich Metadaten, in Blöcken gespeichert. Die maximale BlockgröĂe fĂŒr jedes Dataset wird im Property festgelegt. recordsize (RecordgröĂe). Die RecordgröĂe kann sich Ă€ndern, jedoch beeinflusst dies nicht die GröĂe oder Position von bereits in das Dataset geschriebenen Blöcken â sie gilt nur fĂŒr neue Blöcke, die beim Schreiben erstellt werden.
Sofern nicht anders festgelegt, betrĂ€gt die aktuelle Standard-RecordgröĂe 128 KiB. Dies stellt einen gewissen Kompromiss dar, bei dem die Leistung in den meisten FĂ€llen weder ideal noch katastrophal sein wird. Recordsize kann auf jeden Wert von 4K bis 1M eingestellt werden (mit zusĂ€tzlichen Anpassungen recordsize kann sogar noch höher eingestellt werden, was jedoch selten eine gute Idee ist).
Jeder Block verweist nur auf die Daten einer einzigen Datei â Sie können nicht zwei verschiedene Dateien in einen Block quetschen. Jede Datei besteht aus einem oder mehreren Blöcken, abhĂ€ngig von der GröĂe. Wenn die GröĂe der Datei kleiner als die RecordgröĂe ist, wird sie in einem kleineren Block gespeichert â beispielsweise belegt eine 2 KiB Datei im Block nur einen Sektor von 4 KiB auf der Festplatte.
Wenn die Datei groĂ genug ist und mehrere Blöcke benötigt, haben alle EintrĂ€ge mit dieser Datei die GröĂe recordsize â einschlieĂlich des letzten Eintrags, dessen Hauptteil ungenutzter Speicherplatz sein kann. .
Zvols haben keine Eigenschaft recordsize â stattdessen besitzen sie eine Ă€quivalente Eigenschaft volblocksize.
Sektoren
Der letzte, grundlegende Baustein ist der Sektor. Dies ist die kleinste physische Einheit, die von einem SpeichergerĂ€t geschrieben oder gelesen werden kann. Jahrzehntelang wurden in den meisten Festplatten 512-Byte-Sektoren verwendet. In letzter Zeit sind die meisten Festplatten auf 4 KiB-Sektoren konfiguriert, und in einigen â insbesondere SSDs â sind sogar 8 KiB oder noch gröĂere Sektoren zu finden.
Im ZFS-System gibt es eine Eigenschaft, die es ermöglicht, die SektorgröĂe manuell festzulegen. Diese Eigenschaft ashift. Es ist etwas verwirrend, dass ashift eine Potenz von zwei ist. Zum Beispiel, ashift=9 bedeutet eine SektorgröĂe von 2^9 oder 512 Byte.
ZFS fordert vom Betriebssystem detaillierte Informationen zu jedem BlockgerĂ€t an, wenn es einem neuen vdev hinzugefĂŒgt wird, und stellt theoretisch ashift automatisch korrekt auf Basis dieser Informationen ein. Leider lĂŒgen viele Festplatten ĂŒber ihre SektorgröĂe, um die KompatibilitĂ€t mit Windows XP zu wahren, das nicht in der Lage war, Festplatten mit anderen SektorgröĂen zu verstehen.
Das bedeutet, dass ZFS-Administratoren dringend den tatsĂ€chlichen SektorgröĂen ihrer GerĂ€te bekannt sein sollten und diese manuell einstellen mĂŒssen. ashift. Wenn ein zu kleiner ashift eingestellt wird, erhöht sich astronomisch die Anzahl der Lese- und SchreibvorgĂ€nge. Das bedeutet, dass die Schreiboperation fĂŒr 512-Byte-'Sektoren' in einen echten 4 KiB-Sektor erfordert, zuerst den ersten 'Sektor' zu schreiben, dann den 4 KiB-Sektor zu lesen, ihn mit dem zweiten 512-Byte-'Sektor' zu verĂ€ndern, zurĂŒck in den neuen 4 KiB-Sektor zu schreiben und so weiter fĂŒr jede Aufzeichnung.
In der realen Welt betrifft dieser Strafe insbesondere SSDs von Samsung EVO, bei denen ashift=13gilt, jedoch lĂŒgen diese SSDs ĂŒber ihre SektorgröĂe, weshalb standardmĂ€Ăig eingestellt wird. ashift=9. Wenn ein erfahrener Systemadministrator diese Einstellung nicht Ă€ndert, funktioniert dieses SSD langsamer als ein herkömmliches magnetisches HDD.
Im Vergleich dazu gibt es fĂŒr zu groĂe GröĂen ashift praktisch keine Strafe. Es gibt keine spĂŒrbare Leistungsminderung, und der Anstieg des ungenutzten Speicherplatzes ist unendlich gering (oder null, wenn die Kompression aktiviert ist). Daher empfehlen wir dringend, selbst fĂŒr solche Festplatten, die tatsĂ€chlich 512-Byte-Sektoren nutzen, die Einstellung ashift=12 oder sogar ashift=13, um mit Zuversicht in die Zukunft zu blicken.
Die Eigenschaft ashift wird fĂŒr jedes virtuelle vdev-GerĂ€t festgelegt, und nicht fĂŒr den Pool, wie viele fĂ€lschlicherweise denken â und kann nach der Festlegung nicht mehr geĂ€ndert werden. Wenn Sie versehentlich ashift bei der HinzufĂŒgung eines neuen vdev zum Pool verwirrt wurden, haben Sie diesen Pool unwiderruflich mit einem GerĂ€t mit niedriger Leistung kontaminiert, und in der Regel gibt es keinen anderen Ausweg, als den Pool zu löschen und von vorne zu beginnen. Selbst das Entfernen des vdev wird nicht von einer fehlerhaften Einstellung befreien. ashift!
Der Schreibmechanismus

Wenn ein herkömmliches Dateisystem Daten ĂŒberschreiben muss â Ă€ndert es jeden Block dort, wo er sich befindet.

Das Copy-on-Write-Dateisystem speichert eine neue Version des Blocks und entsperrt dann die alte Version.

Im abstrakten Sinne, wenn man die tatsĂ€chliche physische Anordnung der Blöcke ignoriert, vereinfacht sich unser âDatenkometâ zu einem âDatenwurmâ, der von links nach rechts ĂŒber die Karte des verfĂŒgbaren Raums bewegt.

Jetzt haben wir ein gutes VerstĂ€ndnis dafĂŒr, wie Copy-on-Write-Snapshots funktionieren â jeder Block kann mehreren Snapshots zugeordnet werden und bleibt bestehen, bis alle zugehörigen Snapshots gelöscht werden.
Der Copy-on-Write-Mechanismus (CoW) ist das Fundament dessen, was ZFS zu einem so beeindruckenden System macht. Das Grundkonzept ist einfach â wenn Sie ein traditionelles Dateisystem bitten, eine Datei zu Ă€ndern, wird es genau das tun, was Sie verlangen. Wenn Sie jedoch ein Copy-on-Write-Dateisystem bitten, dasselbe zu tun, wird es âOkayâ sagen â aber Sie anlĂŒgen.
Stattdessen speichert das Copy-on-Write-Dateisystem eine neue Version des geĂ€nderten Blocks und aktualisiert dann die Metadaten der Datei, um die Verbindung zum alten Block zu trennen und den gerade geschriebenen neuen Block zu verknĂŒpfen.
Das Trennen des alten Blocks und das VerknĂŒpfen des neuen Blocks erfolgt in einem einzigen Vorgang, weshalb dieser nicht unterbrochen werden kann â wenn Sie die Stromversorgung nach Abschluss dieser Operation unterbrechen, haben Sie eine neue Version der Datei; wenn Sie vorher die Stromversorgung abstellen, haben Sie die alte Version. In jedem Fall entstehen in der Dateisystemstruktur keine Konflikte.
Das Copy-on-Write in ZFS erfolgt nicht nur auf der Ebene des Dateisystems, sondern auch auf der Ebene der Festplattenverwaltung. Das bedeutet, dass ZFS nicht unter einem Schreibfehler leidet () â einem PhĂ€nomen, bei dem der Stripe nur teilweise vor dem Systemausfall geschrieben werden konnte, was zu BeschĂ€digungen des Arrays nach dem Neustart fĂŒhrt. Hier wird der Stripe atomar geschrieben, das vdev ist immer konsistent, und .
ZIL: ZFS Intent Log

Das ZFS-System behandelt synchronisierte SchreibvorgĂ€nge auf spezielle Weise â es speichert sie vorĂŒbergehend, jedoch sofort im ZIL, bevor sie zusammen mit asynchronen SchreibvorgĂ€ngen spĂ€ter dauerhaft geschrieben werden.

Normalerweise werden die im ZIL gespeicherten Daten nach der Speicherung nie wieder abgerufen. Dies ist jedoch nach einem Systemausfall möglich.

SLOG, oder sekundĂ€res LOG-GerĂ€t, ist einfach ein spezielles â und idealerweise sehr schnelles â vdev, wo das ZIL separat vom Hauptspeicher gespeichert werden kann.

Nach einem Ausfall werden alle verschmutzten Daten im ZIL wiederhergestellt â in diesem Fall befindet sich das ZIL auf dem SLOG, sodass sie genau von dort wiederhergestellt werden.
Es gibt zwei Hauptkategorien von Schreiboperationen â synchron (sync) und asynchron (async). FĂŒr die meisten Workloads sind ĂŒberwiegend asynchrone SchreibvorgĂ€nge â das Dateisystem erlaubt es, diese zu aggregieren und gepackt auszugeben, was die Fragmentierung reduziert und die Bandbreite signifikant erhöht.
Synchronisierte SchreibvorgĂ€nge sind eine ganz andere Angelegenheit. Wenn eine Anwendung eine synchronisierte Schreiboperation anfordert, sagt sie dem Dateisystem: 'Du musst dies im nichtflĂŒchtigen Speicher festhalten.' jetzt sofort, und bis dahin kann ich nichts weiter tun.â Daher mĂŒssen die synchronen SchreibvorgĂ€nge sofort auf der Festplatte festgehalten werden â und wenn das die Fragmentierung erhöht oder die Bandbreite verringert, sei es so.
ZFS behandelt synchrone SchreibvorgĂ€nge anders als herkömmliche Dateisysteme â anstatt sie sofort in den regulĂ€ren Speicher zu schreiben, speichert ZFS sie in einem speziellen Speicherbereich, der als ZFS Intent Log (ZIL) bekannt ist. Der Trick dabei ist, dass diese EintrĂ€ge auch im Speicher bleiben, wĂ€hrend sie zusammen mit den regulĂ€ren asynchronen Schreibanforderungen aggregiert werden, um spĂ€ter als völlig normale TXG (Transaction Groups) in den Speicher geschrieben zu werden.
Im normalen Betriebsmodus wird das ZIL geschrieben und nie wieder gelesen. Wenn nach wenigen Augenblicken die EintrÀge aus dem ZIL im regulÀren TXG aus dem RAM in den Hauptspeicher geschrieben werden, werden sie vom ZIL getrennt. Das einzige Mal, dass etwas aus dem ZIL gelesen wird, ist beim Import eines Pools.
Wenn ein ZFS-Fehler auftritt â sei es ein Betriebssystemausfall oder ein Stromausfall â und es sich im ZIL Daten befinden, werden diese Daten beim nĂ€chsten Import des Pools (z.B. beim Neustart des fehlerhaften Systems) gelesen. Alles, was sich im ZIL befindet, wird gelesen, in TXG-Gruppen zusammengefasst, im Hauptspeicher gespeichert und dann im Importprozess vom ZIL abgetrennt.
Eine der Hilfsklassen von vdev wird als LOG oder SLOG bezeichnet, ein sekundĂ€res LOG-GerĂ€t. Es hat die Aufgabe, dem Pool ein separates und idealerweise viel schnelleres vdev-GerĂ€t mit einer sehr hohen SchreibbestĂ€ndigkeit fĂŒr die Speicherung des ZIL zur VerfĂŒgung zu stellen, anstatt das ZIL im Hauptspeicher des vdev zu speichern. Das ZIL verhĂ€lt sich unabhĂ€ngig vom Speicherort gleich, aber wenn das vdev mit LOG eine sehr hohe Schreibgeschwindigkeit hat, werden die synchronen SchreibvorgĂ€nge schneller erfolgen.
Das HinzufĂŒgen eines vdev mit LOG zu einem Pool kann die Leistung von asynchronen SchreibvorgĂ€ngen nicht verbessern â selbst wenn Sie alle SchreibvorgĂ€nge im ZIL mit Hilfe von, sie werden dennoch ebenso wie ohne Protokoll an den Hauptspeicher in TXG gebunden sein und im selben Tempo arbeiten. Die einzige direkte Leistungsverbesserung ist die Verzögerung der synchronen SchreibvorgĂ€nge (da eine höhere Protokollgeschwindigkeit die AusfĂŒhrung von VorgĂ€ngen beschleunigt) sync).
In einer Umgebung, die bereits eine groĂe Anzahl synchroner SchreibvorgĂ€nge erfordert, kann vdev LOG indirekt die asynchrone Schreibgeschwindigkeit und nicht zwischengespeicherte Lesegeschwindigkeit erhöhen. Das Auslagern von ZIL-EintrĂ€gen in einen separaten vdev LOG bedeutet weniger Konkurrenz um IOPS im primĂ€ren Speicher, was die Leistung aller Lese- und SchreibvorgĂ€nge in gewissem MaĂe steigert.
Snapshots
Der Schreibvorgangsspeichermechanismus ist auch eine notwendige Grundlage fĂŒr atomare ZFS-Snapshots und inkrementelle asynchrone Replikation. In einem aktiven Dateisystem gibt es einen Zeigerbaum, der alle EintrĂ€ge mit aktuellen Daten markiert â wenn Sie einen Snapshot erstellen, machen Sie einfach eine Kopie dieses Zeigerbaums.
Wenn in einem aktiven Dateisystem ein Eintrag ĂŒberschrieben wird, schreibt ZFS zuerst eine neue Version des Blocks in ungenutzten Speicherplatz. Danach trennt es die alte Version des Blocks vom aktuellen Dateisystem. Sollte jedoch ein Snapshot auf den alten Block verweisen, bleibt dieser unverĂ€ndert. Der alte Block wird tatsĂ€chlich nicht als freier Speicher wiederhergestellt, bis alle Snapshots, die auf diesen Block verweisen, gelöscht sind!
Replikation

Meine Steam-Bibliothek nahm 2015 158 GiB ein und umfasste 126.927 Dateien. Das ist ziemlich nah an der optimalen Situation fĂŒr rsync â die ZFS-Replikation ĂŒber das Netzwerk war ânurâ 750 % schneller.

In demselben Netzwerk ist die Replikation einer 40-GiB groĂen Windows 7-VM-Image-Datei eine ganz andere Geschichte. Die ZFS-Replikation erfolgt 289-mal schneller als bei rsync â oder ânurâ 161-mal schneller, wenn Sie genug Wissen haben, um rsync mit dem Schalter --inplace aufzurufen.

Wenn das Image einer virtuellen Maschine skaliert wird, skaliert auch das rsync-Probleme mit. Eine GröĂe von 1,9 TiB ist fĂŒr ein modernes Image einer virtuellen Maschine nicht besonders groĂ â jedoch groĂ genug, damit die ZFS-Replikation 1148-mal schneller als rsync ist, selbst mit dem rsync-Argument âinplace.
Sobald Sie verstanden haben, wie Snapshots funktionieren, ist es nicht schwierig, die GrundzĂŒge der Replikation zu erfassen. Da ein Snapshot lediglich ein Zeigerbaum auf die DatenblĂ€tter ist, folgt daraus, dass wir, wenn wir einen zfs send Snapshot erstellen, sowohl diesen Baum als auch alle damit verbundenen DatenblĂ€tter versenden. Wenn wir dies an den zfs send in zfs receive des Zielobjekts ĂŒbergeben, werden sowohl der tatsĂ€chliche Inhalt des Blocks als auch der Zeigerbaum, der auf die Blöcke verweist, in den Ziel-Datensatz geschrieben.
Es wird noch interessanter bei der zweiten zfs send. Jetzt haben wir zwei Systeme, von denen jedes enthÀlt poolname/datasetname@1, und Sie erstellen einen neuen Snapshot poolname/datasetname@2. Daher haben Sie im Quellpool datasetname@1 und datasetname@2, wÀhrend im Zielpool bisher nur der erste Snapshot vorhanden ist. datasetname@1.
Da wir zwischen Quelle und Ziel einen gemeinsamen Snapshot haben datasetname@1, können wir einen inkrementellen zfs send darĂŒber erstellen. Wenn wir dem System sagen zfs send -i poolname/datasetname@1 poolname/datasetname@2, es vergleicht zwei ZeigerbĂ€ume. Alle Zeiger, die nur in @2, verweisen offensichtlich auf neue Blöcke â daher benötigen wir den Inhalt dieser Blöcke.
In einem Remote-System ist die Verarbeitung der inkrementellen send genauso einfach. ZunĂ€chst schreiben wir alle neuen EintrĂ€ge, die im Stream enthalten sind, send, und fĂŒgen dann Verweise auf diese Blöcke hinzu. VoilĂ , wir haben @2 im neuen System!
Die asynchrone inkrementelle ZFS-Replikation stellt eine enorme Verbesserung im Vergleich zu frĂŒheren, nicht snapshotbasierten Methoden wie rsync dar. In beiden FĂ€llen werden nur die geĂ€nderten Daten ĂŒbertragen â aber rsync muss zunĂ€chst hier lesen alle Daten von beiden Seiten von der Festplatte lesen, um die PrĂŒfziffer zu ĂŒberprĂŒfen und zu vergleichen. Im Gegensatz dazu liest die ZFS-Replikation nichts auĂer den ZeigerbĂ€umen â und gegebenenfalls die Blöcke, die im gemeinsamen Snapshot nicht vorhanden sind.
Integrierte Kompression
Der Mechanismus fĂŒr Copy-on-Write vereinfacht auch das System der integrierten Kompression. In traditionellen Dateisystemen ist die Kompression problematisch â sowohl die alte als auch die neue Version der geĂ€nderten Daten befinden sich im selben Raum.
Wenn man einen Datenblock in der Mitte einer Datei betrachtet, der als Megabyte von Nullen bei 0x00000000 beginnt und so weiter, lÀsst er sich sehr leicht auf einen Sektor auf der Festplatte komprimieren. Aber was passiert, wenn wir dieses Megabyte an Nullen durch ein Megabyte unkomprimierbarer Daten, wie JPEG oder pseudorandom Rauschen, ersetzen? Unerwartet benötigt dieses Megabyte an Daten nicht einen, sondern 256 Sektoren mit 4 KiB, und an dieser Stelle auf der Festplatte ist nur ein Sektor reserviert.
ZFS hat dieses Problem nicht, da Ănderungen immer in ungenutztem Speicher geschrieben werden â der ursprĂŒngliche Block nimmt nur einen Sektor von 4 KiB ein, und der neue Eintrag benötigt 256, aber das ist kein Problem â der zuletzt geĂ€nderte Block aus der âMitteâ der Datei wĂŒrde unabhĂ€ngig davon, ob seine GröĂe sich Ă€ndert oder nicht, in ungenutztem Speicher geschrieben werden, daher ist dies fĂŒr ZFS eine ganz normale Situation.
Die integrierte Kompression von ZFS ist standardmĂ€Ăig deaktiviert und das System bietet optionale Algorithmen an â aktuell gehören dazu LZ4, gzip (1-9), LZJB und ZLE.
- LZ4 â ist ein Streaming-Algorithmus, der extrem schnelles Komprimieren und Dekomprimieren sowie Leistungsgewinne fĂŒr die meisten AnwendungsfĂ€lle bietet â sogar auf relativ langsamen CPUs.
- GZIP â ein angesehener Algorithmus, der von allen Nutzern von Unix-Systemen geschĂ€tzt wird. Er kann mit Komprimierungsstufen von 1 bis 9 implementiert werden, wobei die Komprimierungsrate zunimmt und der CPU-Verbrauch ansteigt, je nĂ€her man Stufe 9 kommt. Der Algorithmus eignet sich gut fĂŒr alle textbasierten (oder anderen stark komprimierbaren) AnwendungsfĂ€lle, kann jedoch zu Problemen mit der CPU fĂŒhren â verwenden Sie ihn mit Vorsicht, insbesondere auf höheren Stufen.
- LZJB â der ursprĂŒngliche Algorithmus in ZFS. Er ist veraltet und sollte nicht mehr verwendet werden; LZ4 ĂŒbertrifft ihn in allen Aspekten.
- ZLE â Null-Level-Encoding. Es berĂŒhrt normale Daten ĂŒberhaupt nicht, komprimiert jedoch groĂe Nullfolgen. NĂŒtzlich fĂŒr vollstĂ€ndig nicht komprimierbare DatensĂ€tze (z. B. JPEG, MP4 oder andere bereits komprimierte Formate), da es nicht komprimierbare Daten ignoriert, aber ungenutzten Platz in den endgĂŒltigen Aufzeichnungen komprimiert.
Wir empfehlen die LZ4-Kompression praktisch fĂŒr alle Einsatzszenarien; die LeistungseinbuĂen bei der Verarbeitung nicht komprimierbarer Daten sind minimal, wĂ€hrend der Leistungszuwachs fĂŒr typische Daten erheblich ist. Das Kopieren eines Abbildes einer virtuellen Maschine fĂŒr eine neue Windows-Betriebssysteminstallation (frisch installiert, keine Daten sind noch vorhanden) mit compression=lz4 geschah 27% schneller als mit compression=none, in .
ARC â adaptiver Austauschcache
ZFS ist das einzige moderne Dateisystem, das uns bekannt ist und das sein eigenes Lese-Cache-System verwendet, anstatt sich auf den Seiten-Cache des Betriebssystems zu verlassen, um Kopien von kĂŒrzlich gelesenen Blöcken im Arbeitsspeicher zu speichern.
Obwohl der eigene Cache nicht ohne Probleme ist â ZFS kann nicht so schnell auf neue Anfragen zur Speicherzuweisung reagieren wie der Kernel, weshalb ein neuer Aufruf malloc() zur SpeicherausÂweisung fehlschlagen kann, wenn er RAM benötigt, der momentan vom ARC belegt ist. Aber es gibt gewichtige GrĂŒnde, den eigenen Cache zu verwenden, zumindest derzeit.
Alle gĂ€ngigen modernen Betriebssysteme wie MacOS, Windows, Linux und BSD verwenden fĂŒr die Implementierung des Seiten-Caches den LRU-Algorithmus (Least Recently Used). Dies ist ein einfacher Algorithmus, der einen im Cache gespeicherten Block nach jedem Zugriff «nach oben» in die Warteschlange verschiebt und Blöcke «nach unten» verdrĂ€ngt, um Platz fĂŒr neue Cache-Misshits (Blöcke, die vom Laufwerk und nicht aus dem Cache gelesen werden mĂŒssen) zu schaffen.
Normalerweise funktioniert der Algorithmus ordnungsgemĂ€Ă, jedoch kann in Systemen mit groĂen Arbeitslasten LRU leicht zu thrashing fĂŒhren â dem VerdrĂ€ngen hĂ€ufig benötigter Blöcke, um Platz fĂŒr Blöcke zu schaffen, die niemals wieder aus dem Cache gelesen werden.
 ist ein wesentlich weniger naiver Algorithmus, der als «gewichteter» Cache betrachtet werden kann. Nach jedem Zugriff auf einen im Cache gespeicherten Block wird dieser etwas «schwerer» und es wird schwieriger, ihn zu verdrĂ€ngen â selbst nach der VerdrĂ€ngung wird der Block verfolgt fĂŒr einen bestimmten Zeitraum. Ein Block, der verdrĂ€ngt wurde, aber dann wieder in den Cache gelesen werden muss, wird ebenfalls «schwerer».
Das Endergebnis all dessen ist ein Cache mit einer deutlich höheren Trefferquote â das VerhĂ€ltnis zwischen Cache-Zugriffen (lesen aus dem Cache) und FehlschlĂ€gen (lesen von der Festplatte). Diese Statistik ist Ă€uĂerst wichtig â nicht nur werden Cache-Hits um ein Vielfaches schneller bearbeitet, sondern auch die FehlschlĂ€ge können schneller bearbeitet werden, da mehr Cache-Hits weniger parallele Anfragen an die Festplatte zur Folge haben, was die Verzögerung fĂŒr die verbleibenden FehlschlĂ€ge, die von der Festplatte bearbeitet werden mĂŒssen, verringert.
Fazit
Nachdem wir die grundlegende Semantik von ZFS â wie das Copy-on-Write-Prinzip funktioniert sowie die Beziehungen zwischen Storage-Pools, virtuellen GerĂ€ten, Blöcken, Sektoren und Dateien â untersucht haben, sind wir bereit, die tatsĂ€chliche Leistung anhand realer Zahlen zu besprechen.
Im nÀchsten Teil werden wir die tatsÀchliche Leistung von Pools mit Mirror vdev und RAIDz miteinander vergleichen sowie im Vergleich zu den traditionellen RAID-Topologien des Linux-Kernels, die wir untersucht haben. .
ZunĂ€chst wollten wir uns nur auf die Grundlagen konzentrieren â die ZFS-Topologien selbst â aber nach der so vieler Wir sind bereit, ĂŒber fortgeschrittene Konfigurationen und Tuning von ZFS zu sprechen, einschlieĂlich der Verwendung von unterstĂŒtzenden vdev-Typen wie L2ARC, SLOG und Special Allocation.
Quelle: habr.com
