2009-08-28 17 views
11

Abbiamo bisogno di leggere e contare diversi tipi di messaggi/eseguire alcune statistiche su un file di testo da 10 GB, ad esempio un FIX motore log. Usiamo Linux, 32 bit, 4 CPU, Intel, la codifica in Perl ma la lingua non ha molta importanza.Qual è il modo più veloce per leggere il file da 10 GB dal disco?

Ho trovato alcuni suggerimenti interessanti in di Tim Bray WideFinder project. Tuttavia, abbiamo scoperto che l'uso della mappatura della memoria è intrinsecamente limitato dall'architettura a 32 bit.

Abbiamo provato a utilizzare più processi, che sembra funzionare più velocemente se elaboriamo il file in parallelo utilizzando 4 processi su 4 CPU. L'aggiunta di multi-threading lo rallenta, forse a causa del costo del cambio di contesto. Abbiamo provato a cambiare la dimensione del pool di thread, ma è ancora più lenta della versione semplice multiprocedel .

La parte mappatura della memoria non è molto stabile, a volte prende 80 sec e, talvolta, 7 sec su un file di 2 GB, forse da errori di pagina o qualcosa legato a utilizzo della memoria virtuale. In ogni caso, Mmap non può scalare oltre i 4 GB su un'architettura a 32 bit.

Abbiamo provato Perl's IPC::Mmap e Sys::Mmap. Sembrava anche in Map-Reduce, ma il problema è in realtà legato all'I/O , l'elaborazione stessa è sufficientemente veloce.

così abbiamo deciso di provare a ottimizzare la base di I/O sintonizzando dimensione buffer, tipo, ecc

Can chiunque sia a conoscenza di un progetto esistente in cui questo problema è stato risolto in modo efficiente in qualsiasi lingua/piattaforma puntare a un link utile o suggerire una direzione?

+2

Qual è la prestazione non elaborata su una singola CPU per 2G? Probabilmente è necessario determinare se l'I/O è il problema oi calcoli della CPU. – Cervo

+2

Se sei realmente legato al disco (IO), l'approccio migliore è probabilmente quello di acquistare dischi più veloci, più dischi (in RAID0, RAID5, RAID10, ecc.) O una macchina a 64 bit con sufficiente memoria per archiviare il file un disco RAM. Qualsiasi disco singolo ragionevole dovrebbe essere in grado di tirare 50 MB/sec; più dischi veloci dovrebbero essere in grado di spingerti ad almeno 300MB/sec. – derobert

+1

Ti consiglio di non utilizzare Sys :: Mmap ma File-Map (per i motivi indicati nella documentazione di quest'ultimo). In ogni caso probabilmente non si desidera utilizzare IPC :: Mmap. –

risposta

9

Per la maggior parte del tempo, il limite di I/O non è limitato dalla CPU, pertanto è sufficiente leggere questo file tramite il normale I/O Perl ed elaborarlo in un singolo thread. A meno che tu non provi che puoi fare più I/O rispetto al tuo lavoro con una singola CPU, non perdere tempo con altro. Ad ogni modo, dovresti chiederti: perché sulla Terra c'è questo in un enorme file? Perché sulla Terra non lo dividono in modo ragionevole quando lo generano? Sarebbe più grande la pena di lavorare. Quindi è possibile inserirlo in canali I/O separati e utilizzare più CPU (se non si utilizza una sorta di RAID 0 o NAS o ...).

Misura, non assumere. Non dimenticare di svuotare le cache prima di ogni test. Ricorda che l'I/O serializzato è di una grandezza più veloce di quello casuale.

0

Mi sembra di ricordare un progetto in cui stavamo leggendo file di grandi dimensioni, La nostra implementazione utilizzava il multithreading - fondamentalmente n * worker_threads iniziavano ad incrementare gli offset del file (0, chunk_size, 2xchunk_size, 3x chunk_size ... n-1x chunk_size) e stava leggendo piccoli pezzi di informazioni. Non riesco a ricordare esattamente il nostro ragionamento per questo mentre qualcun altro stava desintonizzando l'intera faccenda: i lavoratori non erano l'unica cosa, ma è grosso modo come lo abbiamo fatto.

Speranza che aiuta

2

hai pensato in streaming il file e filtrando in un file secondario risultati interessanti? (Ripeti finché non hai un file di dimensioni gestibili).

3

Forse avete già letto questo thread del forum, ma se non:

http://www.perlmonks.org/?node_id=512221

Descrive utilizzando Perl per farlo linea per linea, e gli utenti sembrano pensare Perl è perfettamente in grado di esso.

Oh, è possibile elaborare il file da un array RAID? Se si dispone di diversi dischi con mirroring, è possibile migliorare la velocità di lettura. La concorrenza per le risorse del disco può essere ciò che rende il tentativo di più thread non funziona.

Buona fortuna.

3

Mi piacerebbe saperne di più sul contenuto del file, ma non sapendo che è testo, questo sembra un eccellente tipo di problema con MapReduce.

PS, la lettura più veloce di qualsiasi file è una lettura lineare. cat file > /dev/null dovrebbe essere la velocità di lettura del file.

+3

Infatti; il mio collega che lavorava su un problema simile stava usando i tempi di cat per rintracciare altri problemi nelle velocità di lettura dei file. NFS è stato un orribile succhiare. :( –

1

Fondamentalmente è necessario "Dividere e conquistare", se si dispone di una rete di computer, quindi copiare il file 10G sul maggior numero possibile di PC client, ottenere che ciascun PC client legga un offset del file. Per ulteriore vantaggio, ottenere OGNI PC per implementare il multi-threading oltre alla lettura distribuita.

+3

"il problema è davvero legato all'IO" <--- buona fortuna copiare il file su una macchina più veloce di quanto i dischi possano leggere. – derobert

1

Analizzare il file una volta, leggendo una riga dopo l'altra. Metti i risultati in una tabella in un database decente. Esegui tutte le query che desideri. Dai da mangiare regolarmente alla bestia con i nuovi dati in arrivo.

Realizzare che la manipolazione di un file da 10 Gb, il suo trasferimento attraverso la rete (anche se locale), l'esplorazione di soluzioni complicate ecc. Richiedono tempo.

+2

Il database dei feed e le query di esecuzione possono richiedere più tempo rispetto a tutte le elaborazioni in perl. È dalla mia esperienza che usi anche il caricamento di massa e MySQL, che è uno degli approcci più veloci che puoi usare.) –

+1

Una volta ottenuti i dati in un database * decente *, è possibile eseguire tutte le query desiderate (anche quelle che non sapevate che potreste voler eseguire) con un piccolo costo aggiuntivo. –

1

Ho un collega che ha velocizzato la lettura del FIX andando a Linux a 64 bit. Se è qualcosa che valga la pena, lascia un po 'di soldi per avere un hardware più elaborato.

4

Tutto dipende dal tipo di preelaborazione che è possibile eseguire e quando. Su alcuni dei sistemi che abbiamo, abbiamo gzip file di testo di grandi dimensioni, riducendoli da 1/5 a 1/7 della loro dimensione originale. Parte di ciò che rende questo possibile è che non abbiamo bisogno di elaborare questi file fino a qualche ora dopo la loro creazione, e al momento della creazione non abbiamo realmente nessun altro carico sulle macchine.

Il loro trattamento è fatto più o meno alla maniera di zcat thatfiles | nostro processo. (beh, è ​​fatto su socket unix con uno zcat personalizzato). Si scambia tempo CPU per tempo di I/O del disco, e per il nostro sistema che è stato bene ne vale la pena. C'è naturalmente un sacco di variabili che possono rendere questo un design molto povero per un particolare sistema.

1

hmmm, ma cosa c'è di sbagliato nel comando read() in C? Di solito ha un limite di 2 GB, quindi basta chiamarlo 5 volte in sequenza. Dovrebbe essere abbastanza veloce.

1

Se si esegue il collegamento I/O e il file si trova su un singolo disco, non c'è molto da fare. Una semplice scansione lineare a thread singolo su tutto il file è il modo più veloce per estrarre i dati dal disco. L'utilizzo di ampie dimensioni del buffer potrebbe aiutare un po '.

Se si riesce a convincere lo scrittore del file a spogliarlo su più dischi/macchine, si potrebbe pensare al multithreading del lettore (un thread per testina di lettura, ogni thread che legge i dati da una singola striscia).

0

Non è indicato nel problema che la sequenza sia importante o meno.Quindi, dividi il file in parti uguali, diciamo 1 GB ciascuno, e dal momento che utilizzi più CPU, i thread multipli non saranno un problema, quindi leggi ogni file usando thread separati e utilizza RAM di capacità> 10 GB, quindi tutti i tuoi contenuti verrebbe memorizzato nella RAM letto da più thread.

1

Dal momento che detta piattaforma e del linguaggio non importa ...

Se si desidera una prestazione stabile che è veloce come supporto di origine permette, l'unico modo mi rendo conto che questo può essere fatto su Windows è sovrapposto a letture sequenziali allineate con buffer non OS. Probabilmente è possibile ottenere alcuni GB/s con due o tre buffer, oltre a ciò, ad un certo punto è necessario un buffer circolare (uno scrittore, 1 o più lettori) per evitare qualsiasi copia. L'implementazione esatta dipende dal driver/API. Se c'è una copia di memoria in corso sul thread (sia nel kernel che in usermode) che si occupa dell'IO, ovviamente il buffer più grande deve essere copiato, più tempo è sprecato su quello invece di fare l'IO. Quindi la dimensione ottimale del buffer dipende dal firmware e dal driver. Su Windows i buoni valori da provare sono multipli di 32 KB per l'I/O del disco. Il buffering dei file di Windows, il mapping della memoria e tutto ciò aggiungono un sovraccarico. Buono solo se si eseguono (o entrambi) più letture degli stessi dati in modo casuale. Quindi per la lettura di un file di grandi dimensioni in sequenza una sola volta, non si desidera che il sistema operativo esegua il buffer di alcunché o esegua alcuna memcpy. Se si usa C# ci sono anche penalità per chiamare nel sistema operativo a causa del marshalling, quindi il codice di interoperabilità potrebbe richiedere un po 'di ottimizzazione a meno che non si usi C++/CLI.

Alcune persone preferiscono lanciare l'hardware in caso di problemi, ma se si dispone di più tempo rispetto al denaro, in alcuni scenari è possibile ottimizzare le cose per eseguire 100-1000 x meglio su un singolo computer di livello consumer rispetto a 1000 computer con prezzo aziendale. La ragione è che se l'elaborazione è anche sensibile alla latenza, è probabile che l'aggiunta di due core sia l'aggiunta della latenza. Questo è il motivo per cui i conducenti possono spingere gigabyte/s mentre il software aziendale è bloccato a megabyte/s quando tutto è pronto. Qualunque sia la segnalazione, la logica di business e il software aziendale possono probabilmente essere fatti anche a gigabyte/s su due core CPU consumer, se scritti come se fossi tornato negli anni '80 a scrivere un gioco. L'esempio più famoso che ho sentito di approcciare la loro intera logica di business in questo modo è lo scambio LMAX forex, che ha pubblicato alcuni dei loro codici basati su buffer ring, che si dice siano ispirati dai driver delle schede di rete.

Dimentica tutta la teoria, se sei soddisfatto di < 1 GB/s, un possibile punto di partenza su Windows che ho trovato sta guardando il sorgente di file readfile da winimage, a meno che tu non voglia scavare in esempi sdk/driver. Potrebbe essere necessario qualche correzione del codice sorgente per calcolare correttamente perf a velocità SSD. Sperimenta anche con le dimensioni del buffer. Gli switch/h multi-threaded e/o overlapped (porta di completamento) IO con dimensioni buffer ottimali (provare 32,64,128 KB ecc.) Senza buffer di file Windows nella mia esperienza danno migliori risultati durante la lettura da SSD (dati a freddo) mentre simultaneamente elaborazione (utilizzare/a per l'elaborazione di Adler in quanto altrimenti è troppo legata alla CPU).

Problemi correlati