Archivia in modo efficiente centinaia di milioni di file di piccole dimensioni. Soluzione self-hosted

Archivia in modo efficiente centinaia di milioni di file di piccole dimensioni. Soluzione self-hosted

Cara community, questo articolo si concentrerà sull'archiviazione e il recupero efficienti di centinaia di milioni di piccoli file. In questa fase viene proposta la soluzione finale per file system compatibili con POSIX con pieno supporto per i lock, compresi i cluster lock, e apparentemente anche senza stampelle.

Quindi ho scritto il mio server personalizzato per questo scopo.
Nel corso dell'implementazione di questa attività, siamo riusciti a risolvere il problema principale e allo stesso tempo a ottenere risparmi nello spazio su disco e nella RAM, che il nostro file system del cluster consumava senza pietà. In realtà, un tale numero di file è dannoso per qualsiasi file system in cluster.

L'idea è questa:

In parole semplici, i file di piccole dimensioni vengono caricati tramite il server, vengono salvati direttamente nell'archivio e anche letti da esso, mentre i file di grandi dimensioni vengono affiancati. Schema: 1 cartella = 1 archivio, in totale abbiamo diversi milioni di archivi con file di piccole dimensioni e non diverse centinaia di milioni di file. E tutto questo è implementato completamente, senza script o senza inserire file in archivi tar/zip.

Cercherò di essere breve, mi scuso in anticipo se il post sarà lungo.

Tutto è iniziato con il fatto che non riuscivo a trovare al mondo un server adatto che potesse salvare i dati ricevuti tramite il protocollo HTTP direttamente negli archivi, senza gli svantaggi inerenti agli archivi convenzionali e alla memorizzazione di oggetti. E il motivo della ricerca era il cluster Origin di 10 server che era cresciuto su larga scala, in cui si erano già accumulati 250,000,000 di piccoli file, e il trend di crescita non si sarebbe fermato.

Per coloro a cui non piace leggere articoli, un po’ di documentazione è più semplice:

qui и qui.

E docker allo stesso tempo, ora c'è un'opzione 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

Next:

Se i file sono molti, sono necessarie risorse significative e la cosa peggiore è che alcuni di essi vengono sprecati. Ad esempio, quando si utilizza un file system in cluster (in questo caso MooseFS), il file, indipendentemente dalla sua dimensione effettiva, occupa sempre almeno 64 KB. Cioè, per file di 3, 10 o 30 KB, sono necessari 64 KB sul disco. Se ci sono un quarto di miliardo di file, perdiamo da 2 a 10 terabyte. Non sarà possibile creare nuovi file all'infinito, poiché MooseFS ha una limitazione: non più di 1 miliardo con una replica di ciascun file.

All’aumentare del numero di file, è necessaria molta RAM per i metadati. Anche i frequenti dump di metadati di grandi dimensioni contribuiscono all'usura delle unità SSD.

server wZD. Mettiamo le cose in ordine sui dischi.

Il server è scritto in Go. Prima di tutto, dovevo ridurre il numero di file. Come farlo? A causa dell'archiviazione, ma in questo caso senza compressione, poiché i miei file sono solo immagini compresse. In soccorso è venuto BoltDB, che doveva ancora essere eliminato dai suoi difetti, questo si riflette nella documentazione.

In totale, invece di un quarto di miliardo di file, nel mio caso erano rimasti solo 10 milioni di archivi Bolt. Se avessi l'opportunità di modificare l'attuale struttura dei file della directory, sarebbe possibile ridurla a circa 1 milione di file.

Tutti i file piccoli vengono impacchettati negli archivi Bolt, che ricevono automaticamente i nomi delle directory in cui si trovano, e tutti i file di grandi dimensioni rimangono accanto agli archivi; non ha senso impacchettarli, questo è personalizzabile. Quelli piccoli vengono archiviati, quelli grandi rimangono invariati. Il server funziona in modo trasparente con entrambi.

Architettura e caratteristiche del server wZD.

Archivia in modo efficiente centinaia di milioni di file di piccole dimensioni. Soluzione self-hosted

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

Caratteristiche principali:

  • Multithreading;
  • Multiserver, che fornisce tolleranza agli errori e bilanciamento del carico;
  • Massima trasparenza per l'utente o lo sviluppatore;
  • Metodi HTTP supportati: GET, HEAD, PUT e DELETE;
  • Controllo del comportamento di lettura e scrittura tramite intestazioni client;
  • Supporto per host virtuali flessibili;
  • Supporta l'integrità dei dati CRC durante la scrittura/lettura;
  • Buffer semidinamici per un consumo minimo di memoria e un'ottimizzazione ottimale delle prestazioni di rete;
  • Compattazione dei dati differita;
  • Inoltre, viene offerto un archiviatore multi-thread wZA per la migrazione dei file senza interrompere il servizio.

Esperienza reale:

Sto sviluppando e testando il server e l'archiviatore su dati live da molto tempo, ora funziona con successo su un cluster che include 250,000,000 di piccoli file (immagini) situati in 15,000,000 di directory su unità SATA separate. Un cluster di 10 server è un server Origin installato dietro una rete CDN. Per servirlo vengono utilizzati 2 server Nginx + 2 server wZD.

Per coloro che decidono di utilizzare questo server, sarebbe saggio pianificare la struttura delle directory, se applicabile, prima dell'uso. Vorrei fare subito una prenotazione sul fatto che il server non è destinato a stipare tutto in un archivio 1 Bolt.

Test delle prestazioni:

Minore è la dimensione del file zippato, più veloci saranno le operazioni GET e PUT su di esso. Confrontiamo il tempo totale impiegato dal client HTTP per scrivere su file normali e archivi Bolt, oltre che per leggere. Viene confrontato il lavoro con file di dimensioni 32 KB, 256 KB, 1024 KB, 4096 KB e 32768 KB.

Quando si lavora con gli archivi Bolt, viene verificata l'integrità dei dati di ciascun file (viene utilizzato CRC), prima della registrazione e anche dopo la registrazione, si verifica la lettura e il ricalcolo al volo, questo introduce naturalmente ritardi, ma la cosa principale è la sicurezza dei dati.

Ho condotto test delle prestazioni sulle unità SSD, poiché i test sulle unità SATA non mostrano una chiara differenza.

Grafici basati sui risultati dei test:

Archivia in modo efficiente centinaia di milioni di file di piccole dimensioni. Soluzione self-hosted
Archivia in modo efficiente centinaia di milioni di file di piccole dimensioni. Soluzione self-hosted

Come puoi vedere, per i file di piccole dimensioni la differenza nei tempi di lettura e scrittura tra file archiviati e non archiviati è minima.

Otteniamo un quadro completamente diverso quando testiamo la lettura e la scrittura di file di 32 MB di dimensione:

Archivia in modo efficiente centinaia di milioni di file di piccole dimensioni. Soluzione self-hosted

La differenza di tempo tra la lettura dei file è compresa tra 5 e 25 ms. Con la registrazione le cose vanno peggio, la differenza è di circa 150 ms. Ma in questo caso non è necessario caricare file di grandi dimensioni; semplicemente non ha senso farlo; possono vivere separatamente dagli archivi.

*Tecnicamente, puoi utilizzare questo server per attività che richiedono NoSQL.

Metodi di base per lavorare con il server wZD:

Caricamento di un file normale:

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

Caricamento di un file nell'archivio Bolt (se il parametro del server fmaxsize, che determina la dimensione massima del file che può essere incluso nell'archivio, non viene superato; se viene superato, il file verrà caricato come di consueto accanto all'archivio):

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

Download di un file (se sono presenti file con gli stessi nomi sul disco e nell'archivio, durante il download, la priorità viene data per impostazione predefinita al file non archiviato):

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

Download di un file dall'archivio Bolt (forzato):

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

Le descrizioni di altri metodi sono nella documentazione.

Documentazione wZD
Documentazione wZA

Il server attualmente supporta solo il protocollo HTTP; non funziona ancora con HTTPS. Anche il metodo POST non è supportato (non è stato ancora deciso se sia necessario o meno).

Chiunque scavi nel codice sorgente troverà lì il butterscotch, non a tutti piace, ma non ho legato il codice principale alle funzioni del framework web, ad eccezione del gestore di interruzioni, quindi in futuro potrò riscriverlo rapidamente per quasi tutti motore.

ToDo:

  • Sviluppo del proprio replicatore e distributore + geo per la possibilità di utilizzo in sistemi di grandi dimensioni senza file system cluster (Tutto per adulti)
  • Possibilità di recupero inverso completo dei metadati in caso di completa perdita (se si utilizza un distributore)
  • Protocollo nativo per la possibilità di utilizzare connessioni di rete persistenti e driver per diversi linguaggi di programmazione
  • Possibilità avanzate di utilizzo del componente NoSQL
  • Compressioni di diverso tipo (gzip, zstd, snappy) per file o valori all'interno di archivi Bolt e per file normali
  • Crittografia di diverso tipo per file o valori all'interno degli archivi Bolt e per file normali
  • Conversione video lato server ritardata, anche su GPU

Ho tutto, spero che questo server possa essere utile a qualcuno, licenza BSD-3, doppio copyright, poiché se non ci fosse l'azienda dove lavoro, il server non sarebbe stato scritto. Sono l'unico sviluppatore. Sarei grato per eventuali bug e richieste di funzionalità che trovi.

Fonte: habr.com

Aggiungi un commento