Il deterioramento delle prestazioni si verifica quando zpool è molto pieno o molto frammentato. La ragione di ciò è il meccanismo di rilevamento dei blocchi liberi impiegato con ZFS. A differenza di altri file system come NTFS o ext3, non esiste un bitmap di blocco che mostri quali blocchi sono occupati e quali sono liberi. Invece, ZFS divide il tuo zvol in (di solito 200) aree più grandi chiamate "metaslabs" e memorizza gli alberi AVL 1 di informazioni di blocco libero (mappa spaziale) in ogni metaslab. L'albero AVL bilanciato consente una ricerca efficiente di un blocco adatto alla dimensione della richiesta.
Sebbene questo meccanismo sia stato scelto per ragioni di scala, sfortunatamente si è rivelato anche un grande dolore quando si verifica un alto livello di frammentazione e / o utilizzo dello spazio. Non appena tutti i metaslabs trasportano una quantità significativa di dati, si ottiene un gran numero di piccole aree di blocchi liberi rispetto a un piccolo numero di grandi aree quando il pool è vuoto. Se ZFS deve quindi allocare 2 MB di spazio, inizia a leggere e valutare le mappe spaziali di tutti i metaslabs per trovare un blocco adatto o un modo per suddividere i 2 MB in blocchi più piccoli. Questo ovviamente richiede del tempo. Quel che è peggio è il fatto che costerà un sacco di operazioni di I / O poiché ZFS legge davvero tutte le mappe spaziali dai dischi fisici . Per qualsiasi tua scrittura.
Il calo delle prestazioni potrebbe essere significativo. Se ti piacciono le belle foto, dai un'occhiata al post del blog su Delphix che ha alcuni numeri tolti da un pool zfs (semplificato ma ancora valido). Sto spudoratamente rubando uno dei grafici: guarda le linee blu, rosse, gialle e verdi in questo grafico che rappresentano (rispettivamente) pool con capacità del 10%, 50%, 75% e 93% tracciate rispetto alla velocità di scrittura in KB / s mentre si frammenta nel tempo:
Una soluzione rapida e sporca a questo è stata tradizionalmente la modalità di debug del metaslab (basta rilasciare echo metaslab_debug/W1 | mdb -kw
in fase di esecuzione per modificare immediatamente l'impostazione). In questo caso, tutte le mappe spaziali verrebbero mantenute nella RAM del sistema operativo, eliminando il requisito di I / O eccessivo e costoso su ogni operazione di scrittura. In definitiva, questo significa anche che hai bisogno di più memoria, specialmente per grandi pool, quindi è una specie di RAM per lo scambio di cavalli. Il tuo pool da 10 TB probabilmente ti costerà 2-4 GB di memoria 2 , ma sarai in grado di portarlo al 95% di utilizzo senza troppi problemi.
1 è un po 'più complicato, se sei interessato, guarda il post di Bonwick sulle mappe spaziali per i dettagli
2 se hai bisogno di un modo per calcolare un limite superiore per la memoria, usa zdb -mm <pool>
per recuperare il numero di segments
attualmente in uso in ogni metaslab, dividerlo per due per modellare uno scenario peggiore (ogni segmento occupato sarebbe seguito da uno libero ), moltiplicalo per la dimensione del record per un nodo AVL (due puntatori di memoria e un valore, data la natura a 128 bit di zfs e l'indirizzamento a 64 bit sommerebbero fino a 32 byte, sebbene le persone sembrino assumere generalmente 64 byte per alcuni Motivo).
zdb -mm tank | awk '/segments/ {s+=$2}END {s*=32/2; printf("Space map size sum = %d\n",s)}'
Riferimento: lo schema di base è contenuto in questo post di Markus Kovero nella mailing list di zfs-discuss , anche se credo che abbia fatto alcuni errori nel suo calcolo che spero di aver corretto nel mio.
volume
a 8.5T e non pensarci mai più. È corretto?