Archiviazione efficace di centinaia di milioni di piccoli file. Soluzione Self-Hosted

Archiviazione efficace di centinaia di milioni di piccoli file. Soluzione Self-Hosted

Gentile comunità, questo articolo sarà dedicato all'archiviazione e distribuzione efficiente di centinaia di milioni di piccoli file. In questa fase, viene proposto una soluzione finale per i file system compatibili con POSIX, con pieno supporto per il locking, inclusi quelli cluster, e sembra anche senza workaround.

Pertanto, per questo scopo, ho scritto il mio server specializzato.
Durante l'implementazione di questo compito, sono riuscito a risolvere il problema principale e, contemporaneamente, a ottenere un risparmio di spazio su disco e memoria RAM, che la nostra file system cluster consumava in modo implacabile. Infatti, un numero così elevato di file è dannoso per qualsiasi file system cluster.

L'idea è questa:

In parole semplici, i piccoli file vengono caricati tramite il server, vengono salvati direttamente in un archivio e letti da esso, mentre i file più grandi vengono collocati a fianco. Schema: 1 cartella = 1 archivio, quindi abbiamo diversi milioni di archivi con piccoli file, e non solo centinaia di milioni di file. E tutto questo è realizzato in modo completo, senza script e senza distribuire file in archivi tar/zip.

Cercherò di essere conciso, mi scuso in anticipo se il post risulterà denso.

Tutto è iniziato quando non sono riuscito a trovare un server adatto nel mondo, capace di memorizzare i dati ricevuti tramite il protocollo HTTP direttamente in archivi, evitando i difetti associati ai tradizionali archivi e ai sistemi di storage oggettuali. La causa di questa ricerca è stato un cluster Origin, cresciuto a dimensioni notevoli, composto da 10 server e che aveva accumulato già 250.000.000 di piccoli file, con una tendenza alla crescita che non accennava a fermarsi.

Per chi non ama leggere articoli e troverebbe più semplice una breve documentazione:

qui e qui.

E docker insieme, al momento è disponibile solo con nginx all'interno, per ogni evenienza:

docker run -d --restart=always -e host=localhost -e root=/var/storage 
-v /var/storage:/var/storage --name wzd -p 80:80 eltaline/wzd

Avanti:

Se i file sono molto numerosi, sono necessarie risorse significative e, il più frustrante, parte di esse si perde inutilmente. Ad esempio, utilizzando un file system cluster (nel caso specifico, MooseFS), un file, indipendentemente dalle dimensioni effettive, occupa sempre almeno 64 KB. Quindi per file delle dimensioni di 3, 10 o 30 KB, sul disco è necessario allocare 64 KB. Se ci sono 250 milioni di file, perdiamo da 2 a 10 terabyte. Creare nuovi file all'infinito non sarà possibile, poiché in MooseFS c'è un limite: non più di 1 miliardo per ogni replica di ciascun file.

Man mano che il numero di file aumenta, è necessaria molta memoria RAM per i metadati. Inoltre, frequenti grandi dump di metadati contribuiscono all'usura degli SSD.

Server wZD. Facciamo ordine nei dischi.

Il server è scritto in Go. Prima di tutto, dovevo ridurre il numero di file. Come farlo? Attraverso l'archiviazione, ma in questo caso senza compressione, poiché i miei file sono immagini compresse. In aiuto è venuto BoltDB, che ho dovuto anche ottimizzare, come indicato nella documentazione.

Invece di un quarto di miliardo di file, nel mio caso sono rimasti solo 10 milioni di archivi Bolt. Se avessi la possibilità di modificare l'attuale struttura di riempimento delle directory con i file, si potrebbe ridurre fino a circa 1 milione di file.

Tutti i file di piccole dimensioni vengono impacchettati in archivi Bolt, ricevendo automaticamente i nomi delle directory in cui si trovano, mentre i file di grandi dimensioni rimangono accanto agli archivi, non ha senso impacchettarli, questo è configurabile. I piccoli file vengono archiviati, i grandi restano invariati. Il server funziona in modo trasparente sia con l'uno che con l'altro.

Architettura e caratteristiche del server wZD.

Archiviazione efficace di centinaia di milioni di piccoli file. Soluzione Self-Hosted

Il server funziona sotto i sistemi operativi Linux, BSD, Solaris e OSX. Ho testato solo per l'architettura AMD64 su Linux, ma dovrebbe funzionare anche per ARM64, PPC64, MIPS64.

Caratteristiche principali:

  • Multithreading;
  • Multi-server per garantire ridondanza e bilanciamento del carico;
  • Massima trasparenza per l'utente o lo sviluppatore;
  • Metodi HTTP supportati: GET, HEAD, PUT e DELETE;
  • Gestione del comportamento di lettura e scrittura tramite intestazioni client;
  • Supporto per host virtuali configurabili in modo flessibile;
  • Supporto CRC per l'integrità dei dati durante la scrittura/lettura;
  • Buffer semi-dinamici per un consumo minimo di memoria e un'ottimizzazione delle prestazioni di rete;
  • Compattazione dei dati con ritardo;
  • In aggiunta, è disponibile l'archiviatore multithread wZA per la migrazione dei file senza interrompere il servizio.

Esperienza reale:

Ho sviluppato e testato il server e l'archiviatore su dati reali per un lungo periodo; attualmente, è funzionante con successo su un cluster che include 250.000.000 di piccoli file (immagini), situati in 15.000.000 di directory su dischi SATA separati. Il cluster di 10 server funge da server Origin, collocato dietro una rete CDN. Per la sua gestione utilizziamo 2 server Nginx + 2 server wZD.

Per coloro che decidono di utilizzare questo server, è utile pianificare la struttura delle directory prima dell'uso, se applicabile. Preciso subito che il server non è progettato per contenere tutto in un solo archivio Bolt.

Test delle prestazioni:

Minore è la dimensione del file compresso, più veloce sarà l'esecuzione delle operazioni GET e PUT. Confrontiamo il tempo totale di scrittura del client HTTP in file normali rispetto agli archivi Bolt, così come la lettura. Viene confrontato il lavoro con file di dimensioni 32 KB, 256 KB, 1024 KB, 4096 KB e 32768 KB.

Durante l'utilizzo degli archivi Bolt, viene verificata l'integrità dei dati di ciascun file (si utilizza CRC); prima e dopo la scrittura, viene eseguita una lettura on-the-fly e un ricalcolo, il che naturalmente introduce ritardi, ma la cosa più importante è la sicurezza dei dati.

Ho effettuato test di prestazioni su unità SSD, poiché i test su dischi SATA non mostrano differenze chiare.

Grafici sui risultati del test:

Archiviazione efficace di centinaia di milioni di piccoli file. Soluzione Self-Hosted
Archiviazione efficace di centinaia di milioni di piccoli file. Soluzione Self-Hosted

Come si può vedere, per file di dimensioni ridotte la differenza nel tempo di lettura e scrittura tra file compressi e non compressi è minima.

Già durante il test di lettura e scrittura di file di dimensioni 32 MB otteniamo un quadro completamente diverso:

Archiviazione efficace di centinaia di milioni di piccoli file. Soluzione Self-Hosted

La differenza di tempo tra la lettura dei file è compresa tra 5 e 25 ms. Le cose si complicano con la scrittura, dove la differenza è di circa 150 ms. Ma in questo caso non è necessario caricare file di grandi dimensioni, non ha senso, possono esistere separatamente dagli archivi.

*Tecnicamente è possibile utilizzare questo server anche per compiti che richiedono NoSQL.

I principali metodi di utilizzo del server wZD:

Caricamento di un file normale:

curl -X PUT --data-binary @test.jpg http://localhost/test/test.jpg

Caricamento di un file in archivio Bolt (se non supera il parametro del server fmaxsize, che definisce la dimensione massima del file che può essere incluso nell'archivio; in caso contrario, il file verrà caricato normalmente accanto all'archivio):

curl -X PUT -H "Archive: 1" --data-binary @test.jpg http://localhost/test/test.jpg

Scaricamento di un file (se ci sono file con nomi identici sia sul disco che nell'archivio, al momento del download la priorità per impostazione predefinita viene data al file non archiviato):

curl -o test.jpg http://localhost/test/test.jpg

Scaricamento forzato di un file dall'archivio Bolt:

curl -o test.jpg -H "FromArchive: 1" http://localhost/test/test.jpg

La descrizione di altri metodi è disponibile nella documentazione.

Documentazione wZD
Documentazione wZA

Il server attualmente supporta solo il protocollo HTTP, HTTPS non è ancora operativo. Inoltre, non supporta il metodo POST (non è ancora stato deciso se sia necessario o meno).

Chi scaverà nel codice sorgente troverà un caramello, che non a tutti piace, ma non ho legato il codice principale alle funzioni del framework web, tranne che per il gestore delle interruzioni, quindi in futuro posso riscriverlo rapidamente su quasi qualsiasi motore.

ToDo:

  • Sviluppo di un replicatore e distributore personalizzato + geolocalizzazione per l'utilizzo in grandi sistemi senza file system clusterizzati (tutto in modo professionale)
  • Possibilità di recupero completo e reversibile dei metadati in caso di perdita totale (in caso di utilizzo del distributore)
  • Protocollo nativo per garantire connessioni di rete permanenti e driver per diversi linguaggi di programmazione
  • Funzionalità avanzate per l'utilizzo delle componenti NoSQL
  • Compressioni di diversi tipi (gzip, zstd, snappy) per file o valori all'interno di archivi Bolt e per file normali
  • Crittografia di diversi tipi per file o valori all'interno di archivi Bolt e per file normali
  • Conversione video server-side posticipata, inclusa quella su GPU

Ho finito, spero che questo server possa tornare utile a qualcuno, licenza BSD-3, copyright doppio, poiché senza l'azienda in cui lavoro non avrei scritto il server. Sono lo sviluppatore unico. Apprezzerò eventuali bug trovati e richieste di funzionalità.

Fonte: habr.com

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