
Ciao, di recente mi è capitato di affrontare un'interessante sfida nel configurare uno storage per il backup di un gran numero di dispositivi a blocchi.
Ogni settimana eseguiamo il backup di tutte le macchine virtuali nel nostro cloud, quindi è fondamentale gestire migliaia di backup e farlo nel modo più rapido ed efficace possibile.
Sfortunatamente, le configurazioni standard RAID5, RAID6 in questo caso non sono adatte poiché il processo di ripristino su dischi così grandi come i nostri sarebbe incredibilmente lungo e probabilmente non si concluderebbe mai.
Esaminiamo quali alternative ci sono:
è l'equivalente di RAID5, RAID6, ma con un livello di parità configurabile. In questo caso, il backup non avviene a blocchi, ma per ogni singolo oggetto. Il modo più semplice per provare l'erasure coding è implementare .
è una funzionalità di ZFS attualmente non rilasciata. A differenza di RAIDZ, DRAID ha un blocco di parità distribuito e, durante il ripristino, utilizza immediatamente tutti i dischi dell'array, il che consente di gestire meglio i guasti dei dischi e di riprendersi più rapidamente dopo un'interruzione.


Abbiamo a disposizione un server Fujitsu Primergy RX300 S7 con processore Intel Xeon CPU E5-2650L 0 @ 1.80GHz, nove schede di memoria RAM Samsung DDR3-1333 8Gb PC3L-10600R ECC Registered (M393B1K70DH0-YH9), scaffale disco Supermicro SuperChassis 847E26-RJBOD1, collegato tramite Dual LSI SAS2X36 Expander e 45 dischi Seagate ST6000NM0115-1YZ110 per 6TB ognuno.
Prima di prendere qualsiasi decisione, è fondamentale testare tutto adeguatamente.
Per questo, mi sono preparato e ho condotto test su diverse configurazioni. Ho utilizzato minio, che fungeva da backend S3, eseguendolo in diverse modalità con un numero variabile di target.
Ho principalmente testato il caso di minio con erasure coding rispetto a software RAID utilizzando lo stesso numero di dischi e dischi di parità, cioè: RAID6, RAIDZ2 e DRAID2.
Per vostra informazione: quando eseguite minio con un solo target, minio opera in modalità S3-gateway, presentando il vostro file system locale come storage S3. Se eseguite minio specificando più target, si attiva automaticamente la modalità di Erasure Coding, che distribuisce i dati tra i vostri target fornendo tolleranza ai guasti.
Per impostazione predefinita, minio suddivide i target in gruppi di 16 dischi, con 2 parità per ciascun gruppo. Ciò significa che possono guastarsi contemporaneamente due dischi senza perdere dati.
Per testare le prestazioni, ho utilizzato 16 dischi da 6TB ciascuno e ho scritto su di essi piccoli oggetti di dimensione 1MB. Questo descriveva con massima precisione il nostro carico futuro, poiché tutti gli strumenti di backup moderni suddividono i dati in blocchi di alcuni megabyte e li scrivono in questo modo.
Per eseguire il benchmark, è stata utilizzata l'utile s3bench, eseguita su un server remoto che inviava a minio decine di migliaia di oggetti in cento flussi. Successivamente, ha tentato di richiederli indietro allo stesso modo.
I risultati del benchmark sono presentati nella tabella seguente:

Come possiamo vedere, minio in modalità erasure coding nativa funziona significativamente peggio in scrittura rispetto a minio avviato sopra RAID6 software, RAIDZ2 e DRAID2 nella stessa configurazione.
Separatamente, mi di testare minio su ext4 vs XFS. Sorprendentemente, per il mio tipo di carico, XFS si è rivelato significativamente più lento rispetto a ext4.
Nella prima serie di test, Mdadm ha mostrato un superiore rispetto a ZFS, ma più avanti , che è possibile migliorare le prestazioni di ZFS impostando le seguenti opzioni:
xattr=sa atime=off recordsize=1Me dopo questo i test con ZFS sono migliorati significativamente.
Si può anche notare che DRAID non offre un vantaggio significativo in termini di prestazioni rispetto a RAIDZ, ma teoricamente dovrebbe essere molto più sicuro.
Nei due test finali ho anche cercato di trasferire i metadati (special) e ZIL (log) su uno specchio da SSD. Tuttavia, il trasferimento dei metadati non ha fornito un miglioramento significativo nella velocità di scrittura, e quando ho trasferito ZIL, i miei hanno raggiunto il limite con un utilizzo del 100%, quindi considero questo test fallito. Non escludo che se avessi avuto SSD più veloci, questo potrebbe migliorare notevolmente i miei risultati, ma purtroppo non li avevo.
Alla fine ho deciso di mantenere DRAID e, nonostante il suo stato beta, è la soluzione più veloce ed efficace per il nostro caso.
Ho creato un semplice DRAID2 in configurazione con tre gruppi e due spare distribuiti:
# zpool status data
pool: data
state: ONLINE
scan: none requested
config:
NAME STATE READ WRITE CKSUM
data ONLINE 0 0 0
draid2:3g:2s-0 ONLINE 0 0 0
sdy ONLINE 0 0 0
sdam ONLINE 0 0 0
sdf ONLINE 0 0 0
sdau ONLINE 0 0 0
sdab ONLINE 0 0 0
sdo ONLINE 0 0 0
sdw ONLINE 0 0 0
sdak ONLINE 0 0 0
sdd ONLINE 0 0 0
sdas ONLINE 0 0 0
sdm ONLINE 0 0 0
sdu ONLINE 0 0 0
sdai ONLINE 0 0 0
sdaq ONLINE 0 0 0
sdk ONLINE 0 0 0
sds ONLINE 0 0 0
sdag ONLINE 0 0 0
sdi ONLINE 0 0 0
sdq ONLINE 0 0 0
sdae ONLINE 0 0 0
sdz ONLINE 0 0 0
sdan ONLINE 0 0 0
sdg ONLINE 0 0 0
sdac ONLINE 0 0 0
sdx ONLINE 0 0 0
sdal ONLINE 0 0 0
sde ONLINE 0 0 0
sdat ONLINE 0 0 0
sdaa ONLINE 0 0 0
sdn ONLINE 0 0 0
sdv ONLINE 0 0 0
sdaj ONLINE 0 0 0
sdc ONLINE 0 0 0
sdar ONLINE 0 0 0
sdl ONLINE 0 0 0
sdt ONLINE 0 0 0
sdah ONLINE 0 0 0
sdap ONLINE 0 0 0
sdj ONLINE 0 0 0
sdr ONLINE 0 0 0
sdaf ONLINE 0 0 0
sdao ONLINE 0 0 0
sdh ONLINE 0 0 0
sdp ONLINE 0 0 0
sdad ONLINE 0 0 0
spares
s0-draid2:3g:2s-0 AVAIL
s1-draid2:3g:2s-0 AVAIL
errors: No known data errorsBene, abb smakando lo storage, ora parliamo di cosa useremo per il backup. Qui voglio subito parlare di tre soluzioni che ho potuto provare, ovvero:
— fork , una soluzione specializzata per il backup di dispositivi a blocchi, ha una stretta integrazione con Ceph. È in grado di recuperare le differenze tra i snapshot e creare un backup incrementale da esse. Supporta un'ampia gamma di backend di archiviazione, sia locali che S3. Richiede un database separato per memorizzare la tabella hash di deduplicazione. Tra i suoi svantaggi: è scritto in Python e ha un'interfaccia a riga di comando leggermente non reattiva.
— fork , un mezzo ben noto e collaudato per il backup, in grado di salvare i dati e di deduplicarli in modo efficiente. Può memorizzare i backup sia localmente che su un server remoto tramite scp. È in grado di eseguire il backup di dispositivi a blocchi se avviato con il flag --special, tra i suoi svantaggi: durante la creazione di un backup, il repository viene completamente bloccato, quindi è consigliabile creare un repository separato per ogni macchina virtuale, ma in realtà non è un problema, dato che vengono creati molto facilmente.
— un progetto in rapida crescita, scritto in Go, sufficientemente veloce e supporta un gran numero di backend per lo storage, tra cui sia lo storage locale che scp, S3 e molto altro. È importante notare che esiste un specificamente creato per restic, che consente di esportare lo storage per un utilizzo remoto nel modo più rapido possibile. Tra tutte le opzioni, questa mi è piaciuta di più. Supporta il backup da stdin. Ha pochi svantaggi evidenti, ma ci sono alcune peculiarità:
In primo luogo, ho provato a usarlo in modalità repository condiviso per tutte le macchine virtuali (come Benji) e ha funzionato abbastanza bene, ma le operazioni di ripristino richiedevano un tempo piuttosto lungo, poiché ogni volta prima del ripristino, restic cerca di leggere i metadati di tutti i backup. Questo problema è stato facilmente risolto, come per borg, creando un repository separato per ogni macchina virtuale. Questo approccio si è rivelato molto efficace anche per la gestione dei backup. I repository isolati possono avere una password separata per l'accesso ai dati, e inoltre, non dobbiamo temere che il repository globale possa danneggiarsi in qualche modo. Creare nuovi repository è semplice quanto in borg backup.
In ogni caso, la deduplicazione avviene solo rispetto alla versione precedente del backup; il backup precedente è determinato dal percorso per il backup specificato, quindi se stai eseguendo il backup di oggetti diversi da stdin in un repository condiviso, non dimenticare di specificare l'opzione
--stdin-filename, oppure specificare esplicitamente ogni volta l'opzione--parent.
In secondo luogo, il ripristino su stdout richiede significativamente più tempo rispetto al ripristino su un file system a causa della sua parallelità. In futuro, è prevista una maggiore integrazione dei backup per i dispositivi di blocco.
In terzo luogo, al momento è consigliato utilizzare , poiché la versione 0.9.6 ha un bug che causa un lungo ripristino di file di grandi dimensioni.
Per testare l'efficacia del backup e la velocità di scrittura/ripristino da un backup, ho creato un repository separato e ho provato a eseguire il backup di una piccola immagine di una macchina virtuale (21 GB). Sono stati eseguiti due backup senza modificare l'originale, utilizzando ciascuna delle soluzioni elencate, per verificare quanto velocemente/lentamente vengono copiati i dati deduplicati.

Come possiamo notare, Borg Backup ha il miglior coefficiente di efficienza per il backup iniziale, ma perde in termini di velocità sia di scrittura che di ripristino.
Restic si è rivelato più veloce di Benji Backup, ma impiega più tempo a ripristinare su stdout e, sfortunatamente, non è ancora in grado di scrivere direttamente su un dispositivo di blocco.
Pesando tutti i pro e i contro, ho deciso di fermarmi a restic con rest-server come la soluzione più comoda e promettente per il backup.
In questo screencast puoi vedere come una connessione da 10 Gbit venga completamente sfruttata durante più operazioni di backup eseguite simultaneamente. Vale la pena notare che l'utilizzo dei dischi non supera il 30% in questa situazione.
Sono estremamente soddisfatto della soluzione ottenuta!
Fonte: habr.com
