Fondamenti di ZFS: sistema di archiviazione e prestazioni

Fondamenti di ZFS: sistema di archiviazione e prestazioni

Questa primavera abbiamo già discusso alcuni temi introduttivi, come ad esempio come verificare la velocità dei tuoi dischi e che cos'è il RAID. Nella seconda abbiamo persino promesso di continuare a esplorare le prestazioni di varie topologie multi-disco in ZFS. Si tratta di un file system di nuova generazione che si sta diffondendo ovunque: da Apple fino a Ubuntu.

Bene, oggi è il giorno perfetto per conoscere ZFS, curiosi lettori. Sappiate solo che, secondo una stima modesta dell'autore di OpenZFS, Matt Arons, "è davvero complicato".

Ma prima di addentrarci nei numeri — e ci saranno, lo prometto — riguardanti tutte le configurazioni a otto dischi di ZFS, dobbiamo parlare di come ZFS archivia i dati su disco. Zpool, vdev e device

Zpool, vdev e device

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Questo diagramma del pool completo include tre vdev ausiliari, uno di ciascun tipo, e quattro per RAIDz2

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Di solito non ci sono motivi per creare un pool di tipi e dimensioni di vdev non corrispondenti — ma se lo desideri, nulla ti impedisce di farlo.

Per comprendere realmente il file system ZFS, è fondamentale esaminare attentamente la sua struttura effettiva. In primo luogo, ZFS combina i tradizionali livelli di gestione dei volumi e del file system. In secondo luogo, utilizza un meccanismo transazionale di copia su scrittura. Queste caratteristiche significano che il sistema è strutturalmente molto diverso dai normali file system e dai RAID. Il primo insieme di blocchi fondamentali da comprendere include: il pool di archiviazione (zpool), il dispositivo virtuale (vdev) e il dispositivo reale (device).

zpool

Il pool di archiviazione zpool è la struttura più alta di ZFS. Ogni pool contiene uno o più dispositivi virtuali. A sua volta, ciascuno di essi contiene uno o più dispositivi reali (device). I pool virtuali sono blocchi autonomi. Un singolo computer fisico può contenere due o più pool separati, ma ciascuno è completamente indipendente dagli altri. I pool non possono condividere dispositivi virtuali.

La ridondanza di ZFS si applica a livello di dispositivi virtuali, non a livello di pool. A livello di pool non c'è alcuna ridondanza: se un qualsiasi dispositivo vdev o un vdev speciale viene perso, allora si perde anche l'intero pool.

I moderni pool di archiviazione possono sopravvivere alla perdita della cache o del registro del dispositivo virtuale, sebbene possano perdere un piccolo numero di dati spazzatura se perdono il registro vdev durante un'interruzione di corrente o un guasto di sistema.

Esiste una comune malinteso secondo cui le 'strisce dati' (stripes) di ZFS vengono scritte su tutto il pool. Questo è errato. Zpool non è affatto un divertente RAID0, è piuttosto un divertente JBOD con un complesso meccanismo di distribuzione variabile.

In gran parte, le scritture vengono distribuite tra i dispositivi virtuali disponibili in base allo spazio libero presente, quindi teoricamente tutti verranno riempiti contemporaneamente. Nelle versioni più recenti di ZFS, viene considerato l'uso corrente (utilizzo) del vdev: se un dispositivo virtuale è significativamente più carico di un altro (ad esempio, a causa di un carico di lettura), verrà temporaneamente saltato per la scrittura, nonostante la presenza della maggiore percentuale di spazio libero.

Il meccanismo di determinazione dell'utilizzo, integrato nei moderni metodi di distribuzione della scrittura di ZFS, può ridurre la latenza e aumentare la larghezza di banda durante periodi di carico insolito - ma questo non carta bianca sull'involontario mescolamento di HDD lenti e SSD veloci in un unico pool. Un pool di questo tipo funzionerà comunque alla velocità del dispositivo più lento, come se fosse interamente composto da tali dispositivi.

vdev

Ogni pool di archiviazione è composto da uno o più dispositivi virtuali (virtual device, vdev). A sua volta, ogni vdev include uno o più dispositivi fisici. La maggior parte dei dispositivi virtuali è utilizzata per la semplice archiviazione dei dati, ma esistono diverse classi ausiliarie di vdev, tra cui CACHE, LOG e SPECIAL. Ognuno di questi tipi di vdev può avere una delle cinque topologie: dispositivo singolo (single-device), RAIDz1, RAIDz2, RAIDz3 o specchio (mirror).

RAIDz1, RAIDz2 e RAIDz3 sono speciali varianti di ciò che i vecchi chiamerebbero RAID con parità doppia (diagonale). 1, 2 e 3 si riferiscono al numero di blocchi di parità assegnati a ciascuna striscia di dati. Invece di dischi separati per garantire la parità, i dispositivi virtuali RAIDz distribuiscono uniformemente questa parità sui dischi. Un array RAIDz può perdere tanti dischi quanti sono i suoi blocchi di parità; se ne perde un altro, andrà in errore e porterà con sé il pool di archiviazione.

Negli dispositivi virtuali a specchio (mirror vdev), ogni blocco è memorizzato su ciascun dispositivo nel vdev. Sebbene i mirror doppi (two-wide) siano i più comuni, in un mirror può esserci qualsiasi numero di dispositivi: nelle installazioni più grandi, per migliorare le prestazioni di lettura e la tolleranza ai guasti, si usano spesso i mirror tripli. Un mirror vdev può resistere a qualsiasi guasto finché almeno un dispositivo nel vdev continua a funzionare.

I vdev singoli, per loro natura, sono pericolosi. Questo dispositivo virtuale non sopravviverà a nessun guasto e, se utilizzato come archiviazione o vdev speciale, la sua rottura comporterà la perdita di tutto il pool. Fate molta, molta attenzione qui.

I dispositivi virtuali CACHE, LOG e SPECIAL possono essere creati secondo una qualsiasi delle topologie sopra menzionate, ma ricordate che la perdita di un dispositivo SPECIAL implica la perdita del pool, quindi si raccomanda vivamente una topologia ridondante.

device

Probabilmente il termine più semplice da comprendere in ZFS è una semplice unità di archiviazione a blocchi. Ricorda che le unità virtuali sono costituite da singole unità e un pool è fatto di unità virtuali.

I dischi, magnetici o a stato solido, sono i dispositivi di archiviazione a blocchi più comuni utilizzati come elementi costitutivi del vdev. Tuttavia, qualsiasi dispositivo con un descrittore in /dev è adeguato, quindi è possibile utilizzare interi array RAID hardware come singole unità.

Un semplice file raw è una delle alternative più importanti tra le unità a blocchi da cui può essere costruito un vdev. I pool di test da file sparsi sono un modo molto comodo per verificare i comandi del pool e vedere quanto spazio è disponibile nel pool o nell'unità virtuale di questa topologia.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Puoi creare un pool di test da file sparsi in pochi secondi, ma non dimenticare di eliminare poi l'intero pool e i suoi componenti.

Supponiamo che tu voglia configurare un server con otto dischi e stia pianificando di utilizzare dischi da 10 TB (~9300 GiB) — ma non sei sicuro di quale topologia si adatti meglio alle tue esigenze. Nell'esempio sopra, costruiamo in pochi secondi un pool di test da file sparsi — e ora sappiamo che un RAIDz2 vdev di otto dischi da 10 TB offre 50 TiB di capacità utile.

Un altro tipo speciale di dispositivo è lo SPARE (di riserva). I dispositivi hot-swap, a differenza dei normali dispositivi, appartengono all'intero pool e non a un singolo dispositivo virtuale. Se un vdev nel pool si guasta e un dispositivo di riserva è connesso al pool e disponibile, si unisce automaticamente al vdev danneggiato.

Dopo essersi unito al vdev danneggiato, il dispositivo di riserva inizia a ricevere copie o ricostruzioni dei dati che dovrebbero essere sul dispositivo assente. Nel RAID tradizionale questo è chiamato ricostruzione, mentre in ZFS è noto come «ripristino della ridondanza».

È importante notare che i dispositivi di riserva non sostituiscono permanentemente i dispositivi guasti. Sono solo una sostituzione temporanea per ridurre il tempo durante il quale si osserva la degradazione del vdev. Dopo che l'amministratore ha sostituito il dispositivo guasto del vdev, viene ripristinata la ridondanza su questo dispositivo permanente, e lo SPARE viene disconnesso dal vdev e torna a funzionare come riserva per l'intero pool.

Set di dati, blocchi e settori

Il prossimo insieme di blocchi costitutivi da comprendere nel nostro viaggio attraverso ZFS riguarda più il modo in cui i dati sono organizzati e memorizzati, piuttosto che l'hardware stesso. Qui stiamo saltando alcuni livelli — come i metaslab — per non sovraccaricare i dettagli, mantenendo una comprensione della struttura generale.

Set di dati (dataset)

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Quando creiamo un set di dati per la prima volta, esso mostra tutto lo spazio disponibile nel pool. Poi impostiamo una quota e cambiamo il punto di montaggio. Magia!

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Zvol è per la maggior parte un semplice set di dati, privo del proprio strato di file system, che qui sostituiamo con un file system ext4 del tutto normale.

Un dataset ZFS è approssimativamente simile a un normale file system montato. Come un file system tradizionale, a prima vista sembra "solo un'altra cartella". Ma, come per i file system montati convenzionali, ogni dataset ZFS ha il proprio insieme di proprietà di base.

Innanzitutto, un dataset può avere una quota assegnata. Se imposti zfs set quota=100G poolname/datasetname, non potrai scrivere nella cartella montata /poolname/datasetname più di 100 GiB.

Hai notato la presenza — e l'assenza — delle barre all'inizio di ogni riga? Ogni dataset ha un suo posto sia nella gerarchia ZFS che nella gerarchia di montaggio del sistema. Nella gerarchia ZFS non ci sono barre iniziali — inizi con il nome del pool e poi il percorso da un dataset all'altro. Ad esempio, pool/parent/child per un dataset chiamato child sotto il dataset genitore parent nel pool con un nome creativo pool.

Per impostazione predefinita, il punto di montaggio del dataset sarà equivalente al suo nome nella gerarchia ZFS, con una barra all'inizio — il pool chiamato pool verrà montato come /pool, il dataset parent sarà montato in /pool/parent, e il dataset figlio child verrà montato in /pool/parent/child. Tuttavia, il punto di mount del dataset può essere modificato.

Se indichiamo zfs set mountpoint=/lol pool/parent/child, allora il dataset pool/parent/child sarà montato nel sistema come /lol.

Oltre ai dataset, dobbiamo menzionare i volumi (zvols). Un volume è quasi equivalente a un dataset, ad eccezione del fatto che non ha effettivamente un file system — è semplicemente un dispositivo a blocchi. Puoi, ad esempio, creare un zvol chiamato mypool/myzvol, poi formattarlo con un file system ext4, per poi montare questo file system — ora hai un file system ext4, ma con tutte le funzionalità di sicurezza di ZFS! Potrebbe sembrare sciocco su un singolo computer, ma ha molto più senso come backend nell'esportazione di un dispositivo iSCSI.

Blocchi

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Un file è rappresentato da uno o più blocchi. Ogni blocco è memorizzato su un dispositivo virtuale. La dimensione del blocco di solito corrisponde al parametro recordsize, ma può essere ridotta a 2^ashift, se contiene metadati o un file di piccole dimensioni.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Noi veramente, davvero non scherziamo riguardo al enorme danno alle prestazioni se impostiamo un ashift troppo piccolo.

Nel pool ZFS, tutti i dati, comprese le metadata, vengono memorizzati in blocchi. La dimensione massima del blocco per ogni set di dati è definita nella proprietà recordsize (dimensione del record). La dimensione del record può variare, ma ciò non cambierà la dimensione o la posizione di eventuali blocchi già scritti nel set di dati — si applica solo ai nuovi blocchi man mano che vengono scritti.

Se non diversamente specificato, la dimensione del record corrente per impostazione predefinita è 128 KiB. Questa è una sorta di compromesso, dove le prestazioni non saranno ottimali, ma nemmeno terribili nella maggior parte dei casi. Recordsize può essere impostato su qualsiasi valore da 4K a 1M (con impostazioni aggiuntive recordsize può essere impostato ancora più in alto, ma di solito non è una buona idea).

Ogni blocco fa riferimento ai dati di un solo file — non puoi comprimere due file diversi in un solo blocco. Ogni file è composto da uno o più blocchi, a seconda delle dimensioni. Se la dimensione del file è inferiore alla dimensione del record, verrà memorizzato in un blocco di dimensioni inferiori — ad esempio, un blocco con un file di 2 KiB occuperà solo un settore di 4 KiB sul disco.

Se il file è sufficientemente grande e richiede più blocchi, allora tutte le voci relative a questo file avranno la dimensione recordsize — inclusa l'ultima voce, la cui parte principale potrebbe risultare spazio non utilizzato.

I volumi zvol non hanno la proprietà recordsize — invece, hanno una proprietà equivalente volblocksize.

Settori

L'ultimo e più fondamentale elemento costitutivo è il settore. Questa è l'unità fisica più piccola che può essere scritta o letta dal dispositivo di base. Per decenni, la maggior parte dei dischi ha utilizzato settori da 512 byte. Negli ultimi tempi, la maggior parte dei dischi è configurata per settori da 4 KiB, e in alcuni — specialmente gli SSD — settori da 8 KiB o anche di più.

Nel sistema ZFS c'è una proprietà che consente di impostare manualmente la dimensione del settore. Questa proprietà ashift. È un po' confuso, poiché ashift è una potenza di due. Ad esempio, ashift=9 indica una dimensione del settore di 2^9, ossia 512 byte.

ZFS richiede al sistema operativo informazioni dettagliate su ogni dispositivo di blocco quando viene aggiunto a un nuovo vdev e, teoricamente, imposta automaticamente ashift in modo corretto in base a queste informazioni. Sfortunatamente, molti dischi mentono sulle loro dimensioni di settori per mantenere la compatibilità con Windows XP (che non era in grado di comprendere dischi con dimensioni di settore diverse).

Ciò significa che è fortemente consigliato all'amministratore di ZFS conoscere le reali dimensioni di settore dei propri dispositivi e impostarle manualmente. ashift. Se ashift è impostato troppo basso, il numero di operazioni di lettura/scrittura aumenta in modo astronomico. Scrivere 'settori' da 512 byte in un settore reale da 4 KiB implica la necessità di scrivere il primo 'settore', quindi leggere il settore da 4 KiB, modificarlo con il secondo 'settore' da 512 byte, scriverlo di nuovo in un nuovo settore da 4 KiB e così via per ogni scrittura.

Nel mondo reale, questa penalizzazione colpisce i solid state drive Samsung EVO, per cui dovrebbe applicarsi ashift=13, ma questi SSD mentono sulle loro dimensioni di settore, e quindi viene impostato per impostazione predefinita ashift=9. Se un amministratore di sistema esperto non modifica questo parametro, allora questo SSD funziona più lentamente di un normale HDD magnetico.

A titolo di confronto, non c'è praticamente alcuna penalità per dimensioni eccessive. ashift Non c'è un reale abbassamento delle prestazioni, e l'aumento dello spazio inutilizzato è infinitesimale (o pari a zero se la compressione è attivata). Pertanto, raccomandiamo vivamente di installare anche su quei dischi che utilizzano realmente settori da 512 byte ashift=12 o addirittura ashift=13, per guardare fiduciosamente al futuro.

Questa impostazione ashift è applicata a ogni dispositivo virtuale vdev, e non al pool, come molti erroneamente pensano — e non può essere modificata dopo l'installazione. Se accidentalmente hai impostato ashift quando aggiungi un nuovo vdev al pool, hai compromesso irreversibilmente questo pool con un dispositivo a bassa prestazione e, in genere, non c'è altra soluzione che distruggere il pool e ricominciare da capo. Anche la rimozione del vdev non salverà da una configurazione errata. ashift!

Il meccanismo di copia in scrittura

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Se a un normale file system serve riscrivere i dati, modifica ogni blocco dove si trova.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Il file system con copia alla scrittura registra una nuova versione del blocco e poi sblocca la versione precedente.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
In senso astratto, ignorando la reale posizione fisica dei blocchi, la nostra 'cometa dei dati' si semplifica in un 'verme dei dati', che si muove da sinistra a destra sulla mappa dello spazio disponibile.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Ora possiamo avere una buona comprensione di come funzionano gli snapshot con copia alla scrittura: ogni blocco può appartenere a più snapshot e rimarrà fino a quando non verranno eliminati tutti gli snapshot associati.

Il meccanismo di copia alla scrittura (Copy on Write, CoW) è la base fondamentale di ciò che rende ZFS un sistema così straordinario. Il concetto principale è semplice: se chiedi a un file system tradizionale di modificare un file, farà esattamente ciò che hai richiesto. Se chiedi a un file system con copia alla scrittura di fare lo stesso, dirà 'va bene' — ma ti mentirà.

Invece, il file system con copia su scrittura registra una nuova versione del blocco modificato e poi aggiorna i metadati del file per rompere il legame con il vecchio blocco e legarsi al nuovo blocco che hai appena scritto.

Il distacco del vecchio blocco e il legame del nuovo avviene in un'unica operazione, quindi non può essere interrotto: se si spegne l'alimentazione dopo che questo avviene, si avrà una nuova versione del file, mentre se si spegne prima, si avrà la vecchia versione. In ogni caso, non ci saranno conflitti nel file system.

La copia su scrittura in ZFS avviene non solo a livello di file system, ma anche a livello di gestione dei dischi. Ciò significa che ZFS non è soggetta al problema dello scrivere un buco (buco nel RAID) — un fenomeno in cui la striscia è stata solo parzialmente registrata prima di un crash del sistema, causando danni all'array dopo il riavvio. Qui la striscia viene scritta in modo atomico, e vdev è sempre coerente, e Bob è tuo zio.

ZIL: il log delle intenzioni di ZFS

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Il sistema ZFS gestisce le scritture sincrone in modo speciale: le memorizza temporaneamente, ma immediatamente, nello ZIL, prima di scriverle in modo permanente insieme alle scritture asincrone.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Di solito, i dati scritti nello ZIL non vengono mai letti di nuovo. Tuttavia, ciò è possibile dopo un guasto del sistema.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
SLOG, o dispositivo di LOG secondario, è semplicemente un vdev speciale – e preferibilmente molto veloce – dove lo ZIL può essere memorizzato separatamente dallo storage principale.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Dopo un guasto, tutti i dati non puliti nello ZIL vengono riprodotti: in questo caso lo ZIL si trova su SLOG, quindi vengono riprodotti proprio da lì.

Ci sono due categorie principali di operazioni di scrittura: sincrone (sync) e asincrone (async). Per la maggior parte dei carichi di lavoro, la stragrande maggioranza delle operazioni di scrittura è asincrona: il file system consente di aggregarle e di emetterle in pacchetti, riducendo la frammentazione e aumentando significativamente la larghezza di banda.

Le scritture sincrone sono un'altra cosa. Quando un'applicazione richiede una scrittura sincrona, comunica al file system: «Devi registrarlo nella memoria non volatile proprio ora, e fino ad allora non posso fare altro”. Pertanto, le registrazioni sincrone devono essere immediatamente registrate su disco — e se questo aumenta la frammentazione o riduce la larghezza di banda, così sia.

ZFS gestisce le registrazioni sincrone in modo diverso rispetto ai normali file system — invece di scriverle immediatamente nello storage ordinario, ZFS le registra in un'area di archiviazione speciale chiamata ZFS Intent Log, o ZIL. Il trucco è che queste registrazioni anche rimangono in memoria, aggregate insieme alle normali richieste di scrittura asincrona, per essere successivamente scritte nello storage come normali TXG (gruppi di transazioni, Transaction Groups).

In condizioni di funzionamento normale, il ZIL viene registrato e mai più letto. Quando, dopo pochi istanti, le registrazioni dal ZIL vengono registrate nello storage principale nei normali TXG dalla memoria, vengono scollegate dal ZIL. L'unico momento in cui qualcosa viene letto dal ZIL è durante l'importazione del pool.

Se si verifica un guasto di ZFS — un guasto del sistema operativo o un'interruzione di corrente — quando ci sono dati nel ZIL, questi dati verranno letti al momento del successivo import del pool (ad esempio, durante il riavvio di un sistema dopo un crash). Tutto ciò che si trova nel ZIL sarà letto, raggruppato in TXG, registrato nell'archivio principale e poi scollegato dal ZIL durante il processo di importazione.

Uno dei classi ausiliarie di vdev si chiama LOG o SLOG, un dispositivo secondario LOG. Ha un'unica funzione: fornire al pool un dispositivo vdev separato e, preferibilmente, molto più veloce, con un'alta resistenza alla scrittura, per memorizzare il ZIL, invece di memorizzare il ZIL nel principale archivio vdev. Il ZIL si comporta allo stesso modo indipendentemente dalla posizione di archiviazione, ma se il vdev con LOG ha un'elevata performance in scrittura, le scritture sincrone avverranno più rapidamente.

Aggiungere un vdev con LOG al pool in alcun modo può migliorare le prestazioni della scrittura asincrona — anche se si costringono tutte le scritture nel ZIL utilizzando zfs set sync=always, saranno comunque legati allo storage principale in TXG nello stesso modo e con lo stesso ritmo di quando non è presente il log. L'unico miglioramento delle prestazioni diretto è la latenza della scrittura sincrona (poiché una maggiore velocità del log accelera l'esecuzione delle operazioni sync).

Tuttavia, in un ambiente che richiede già un elevato numero di scritture sincrone, vdev LOG può indirettamente accelerare le scritture asincrone e le letture non memorizzate nella cache. Scaricare le registrazioni ZIL in un vdev LOG separato significa meno concorrenza per gli IOPS nello storage primario, il che migliora, in una certa misura, le prestazioni di tutte le operazioni di lettura e scrittura.

Snapshot

Il meccanismo di copia su scrittura è anche una base necessaria per gli snapshot atomici di ZFS e la replica asincrona incrementale. In un file system attivo c'è un albero di puntatori che segna tutte le registrazioni con i dati correnti: quando esegui uno snapshot, stai semplicemente creando una copia di questo albero di puntatori.

Quando una registrazione viene sovrascritta nel file system attivo, ZFS prima scrive una nuova versione del blocco in uno spazio non utilizzato. Successivamente, scollega la vecchia versione del blocco dal file system attuale. Tuttavia, se uno snapshot fa riferimento al vecchio blocco, rimane invariato. Il vecchio blocco non sarà effettivamente restituito come spazio libero finché tutti gli snapshot che fanno riferimento a quel blocco non saranno eliminati!

Replica

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Nel 2015, la mia libreria Steam occupava 158 GiB e includeva 126.927 file. Questa è una situazione piuttosto vicina all'ottimale per rsync: la replica ZFS sulla rete era "solo" il 750% più veloce.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Nella stessa rete, la replica di un file immagine di macchina virtuale Windows 7 da 40 GiB è una storia completamente diversa. La replica ZFS avviene 289 volte più velocemente di rsync — o "solo" 161 volte più veloce, se hai le competenze sufficienti per chiamare rsync con l'opzione —inplace.

Fondamenti di ZFS: sistema di archiviazione e prestazioni
Quando un'immagine della macchina virtuale viene scalata, i problemi di rsync si amplificano di conseguenza. La dimensione di 1,9 TiB non è così grande per un'immagine di macchina virtuale moderna — ma è sufficiente perché la replica ZFS risulti 1148 volte più veloce rispetto a rsync, anche con l'argomento rsync —inplace.

Una volta compreso come funzionano gli snapshot, sarà facile afferrare il concetto di replica. Poiché uno snapshot è semplicemente un albero di puntatori ai record, ne consegue che se creiamo zfs send uno snapshot, inviamo sia questo albero che tutti i record ad esso associati. Quando trasferiamo questo zfs send in zfs receive sull'oggetto di destinazione, registra sia il contenuto effettivo del blocco che l'albero di puntatori che si riferiscono ai blocchi nel dataset di destinazione.

Tutto diventa ancora più interessante al secondo zfs send. Ora abbiamo due sistemi, ciascuno contenente poolname/datasetname@1, e stai creando un nuovo snapshot poolname/datasetname@2. Quindi nel pool di origine hai datasetname@1 e datasetname@2, mentre nel pool di destinazione c'è solo il primo snapshot datasetname@1.

. Poiché abbiamo uno snapshot comune tra sorgente e destinazione, possiamo creare datasetname@1incrementale sopra di esso. Quando parliamo al sistema zfs send sopra di esso. Quando parliamo del sistema zfs send -i poolname/datasetname@1 poolname/datasetname@2, confronta due alberi di puntatori. Qualsiasi puntatore che esiste solo in @2, ovviamente, si riferisce a nuovi blocchi – quindi avremo bisogno del contenuto di questi blocchi.

Nella sistema remota, l'elaborazione dell'incrementale send è altrettanto semplice. Prima scriviamo tutte le nuove voci incluse nel flusso send, e poi aggiungiamo i puntatori a questi blocchi. Ecco fatto, abbiamo @2 nel nuovo sistema!

La replica incrementale asincrona di ZFS è un'enorme miglioria rispetto ai metodi precedenti che non si basano sugli snapshot, come rsync. In entrambi i casi, vengono trasmessi solo i dati modificati – ma rsync deve prima leggere dal disco tutti i dati da entrambe le parti per controllare il checksum e confrontarlo. A differenza di questo, la replica ZFS non legge nulla tranne gli alberi di puntatori – e qualsiasi blocco non rappresentato nell'snapshot comune.

Compressione integrata

Il meccanismo di copia durante la registrazione semplifica anche il sistema di compressione integrato. Nelle tradizionali file system, la compressione è problematica: sia la vecchia versione che la nuova versione dei dati modificati si trovano nello stesso spazio.

Considerando un frammento di dati a metà file, che inizia la sua vita come un megabyte di zeri da 0x00000000 e così via, è molto facile comprimerlo in un unico settore del disco. Ma cosa succede se sostituiamo quel megabyte di zeri con un megabyte di dati non compressi, come JPEG o rumore pseudo-casuale? Improvvisamente, quel megabyte di dati avrà bisogno non di uno, ma di 256 settori da 4 KiB, mentre in quel punto del disco è riservato solo un settore.

ZFS non ha questo problema, poiché le scritture modificate vengono sempre registrate in uno spazio non utilizzato: il blocco originale occupa solo un settore da 4 KiB, mentre la nuova scrittura occuperà 256, ma questo non è un problema; il frammento recentemente modificato della 'metà' del file sarebbe stato registrato in uno spazio non utilizzato indipendentemente dal fatto che la sua dimensione cambiasse o meno, quindi per ZFS si tratta di una situazione del tutto normale.

La compressione ZFS è disabilitata per impostazione predefinita, e il sistema offre algoritmi plug-in — attualmente tra cui LZ4, gzip (1-9), LZJB e ZLE.

  • LZ4 — è un algoritmo di compressione in streaming che offre una compressione e decompressione estremamente rapide, migliorando le prestazioni nella maggior parte dei casi d'uso — anche su CPU piuttosto lente.
  • GZIP — un algoritmo rispettato, conosciuto e amato da tutti gli utenti dei sistemi Unix. Può essere implementato con livelli di compressione da 1 a 9, con un incremento del grado di compressione e dell'uso della CPU man mano che ci si avvicina al livello 9. L'algoritmo è ben adatto per tutte le varianti di utilizzo testuale (o altre estremamente comprimibili), ma altrimenti causa spesso problemi di CPU — usatelo con cautela, soprattutto ai livelli più alti.
  • LZJB — l'algoritmo originale in ZFS. È obsoleto e non dovrebbe più essere utilizzato, LZ4 lo supera in tutti gli aspetti.
  • ZLE — codifica a livello zero, Zero Level Encoding. Essa non altera i dati normali, ma comprime lunghe sequenze di zeri. Utile per set di dati completamente non comprimibili (come JPEG, MP4 o altri formati già compressi), poiché ignora i dati non comprimibili, ma comprime lo spazio inutilizzato nelle registrazioni finali.

Raccomandiamo di utilizzare la compressione LZ4 praticamente per tutte le applicazioni; la penalizzazione delle prestazioni quando si incontrano dati non comprimibili è molto bassa, e il guadagno in prestazioni per i dati tipici è significativo. La copia di un'immagine della macchina virtuale per una nuova installazione del sistema operativo Windows (nuovo sistema operativo installato, nessun dato presente) con compression=lz4 è stata completata il 27% più velocemente rispetto a compression=none, nel questo test del 2015.

ARC — cache di sostituzione adattiva

ZFS è l'unico file system moderno di cui siamo a conoscenza che utilizza un proprio meccanismo di caching della lettura, invece di affidarsi alla cache delle pagine del sistema operativo per memorizzare le copie dei blocchi letti di recente in memoria.

Sebbene la cache interna non sia priva di problemi, ZFS non può rispondere a nuove richieste di allocazione di memoria con la stessa rapidità del kernel, quindi la nuova chiamata malloc() per l'allocazione di memoria può fallire se richiede memoria RAM attualmente occupata dall'ARC. Tuttavia, ci sono solidi motivi per utilizzare una cache interna, almeno al momento.

Tutti i moderni sistemi operativi conosciuti, tra cui MacOS, Windows, Linux e BSD, implementano la cache delle pagine utilizzando l'algoritmo LRU (Least Recently Used). Questo è un algoritmo primitivo che sposta il blocco memorizzato nella cache “in cima alla coda” dopo ogni lettura e espelle i blocchi “in fondo alla coda” quando necessario, per fare spazio a nuovi miss nella cache (blocchi che devono essere letti dal disco, e non dalla cache).

Di solito, l'algoritmo funziona bene, ma nei sistemi con grandi insiemi di dati, LRU porta facilmente a thrashing, espellendo blocchi frequentemente necessari per liberare spazio a favore di blocchi che non verranno mai più letti dalla cache.

ARC — un algoritmo molto meno ingenuo, che può essere considerato come una cache "ponderata". Dopo ogni lettura di un blocco memorizzato nella cache, diventa un po' più "pesante" e viene espulso più difficilmente — e anche dopo l'espulsione, il blocco viene monitorato per un certo periodo di tempo. Un blocco che è stato espulso ma deve poi essere letto nuovamente nella cache diventerà anch'esso "più pesante".

Il risultato finale di tutto ciò è una cache con un rapporto di colpi (hit ratio) molto più elevato — il rapporto tra i colpi nella cache (letture eseguite dalla cache) e i fallimenti (letture dal disco). Questa è una statistica estremamente importante: non solo i colpi della cache vengono gestiti di gran lunga più velocemente, ma anche i fallimenti della cache possono essere elaborati più rapidamente, poiché più colpi nella cache significano meno richieste parallele al disco e quindi meno latenza per quelli rimanenti fallimenti, che devono essere serviti dal disco.

Conclusione

Dopo aver esaminato la semantica di base di ZFS — come funziona la scrittura dei dati e le relazioni tra i pool di archiviazione, i dispositivi virtuali, i blocchi, i settori e i file — siamo pronti a discutere delle prestazioni reali con numeri concreti.

Nella prossima sezione, confronteremo le prestazioni effettive dei pool con vdev mirror e RAIDz, sia tra di loro che rispetto alle tradizionali topologie RAID del kernel Linux che abbiamo studiato. in precedenza.

Inizialmente volevamo solo esaminare le basi — le topologie stesse di ZFS — ma dopo questo saremo pronti a parlare di configurazioni avanzate e ottimizzazione di ZFS, incluso l'uso di tipi di vdev ausiliari come L2ARC, SLOG e Special Allocation.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster