Java: elaborazione di un file di grandi dimensioni contemporaneamente

6

Quindi ad un livello elevato il mio caso d'uso è il seguente -

I periodically (every 24 hours) get a very large file (size can vary from MBs to 10s of GBs) which I need to process within 24 hours. The processing involves reading a record, apply some Business Logic and updating a database with the record.

La soluzione corrente è una versione a thread singolo che

  1. inizialmente legge l'intero file in memoria, cioè legge ogni riga e costruisce un POJO. Quindi in sostanza crea una grande lista
  2. Quindi itera sull'elenco e applica la logica di business su ciascun Pojo e li salva nel database

Funziona su file di piccole dimensioni con meno di 10 milioni di record. Ma poiché i sistemi si stanno ridimensionando, stiamo diventando più carichi, ad esempio file più grandi (con > 100 milioni di record occasionalmente). In questo scenario vediamo i timeout, ovvero non siamo in grado di elaborare l'intero file entro 24 ore

Quindi ho intenzione di aggiungere un po 'di concorrenza qui.

Una soluzione semplice sarebbe -

  1. Leggi l'intero file in memoria (crea POJO per ogni record, come facciamo attualmente) o leggi ogni record uno per uno e crea POJO
  2. Creazione di thread per elaborare simultaneamente questi POJO.

Questa soluzione sembra semplice, l'unico lato negativo che vedo è che l'analisi dei file potrebbe richiedere del tempo poiché è a thread singolo (la RAM non è un problema, io uso un'istanza EC2 piuttosto grande).

Un'altra soluzione potrebbe essere -

  1. In qualche modo spezza il file in più file secondari
  2. Elabora ogni file in parallelo

Sembra un po 'complicato dal momento che dovrei suddividere il file in più file più piccoli.

Qualsiasi input sui suggerimenti qui sugli approcci sarebbe ben accetto.

    
posta AgentX 28.11.2016 - 14:49
fonte

2 risposte

13

Il modo più efficiente di farlo è:

  • Avere un singolo thread che legge il file di input. I dischi rigidi sono più veloci durante la lettura sequenziale.
  • fai non leggerlo in memoria tutto in una volta! Questo è un enorme spreco di memoria che potrebbe essere usato molto meglio per velocizzare l'elaborazione!
  • Invece, fai in modo che questo thread singolo legga un pacchetto di voci (forse 100, forse 1000, questo è un parametro di ottimizzazione) contemporaneamente e invialo a una discussione da elaborare. Se ogni riga rappresenta un record, il thread di lettura può rinviare tutta l'analisi (diversa dalla ricerca di newline) ai thread di elaborazione. Ma anche se no, è molto improbabile che l'analisi dei record sia il collo di bottiglia.
  • Gestisci il thread tramite una dimensione fissa pool di thread , scegli la dimensione in base al numero di core della CPU sulla macchina, o forse un po 'di più.
  • Se il tuo database è un database SQL, assicurati che i singoli thread accedano al database attraverso un pool di connessioni e facciano tutti gli aggiornamenti DB per un fascio di voci in una singola transazione e utilizzando inserimenti batch.

Potresti utilizzare Spring Batch per questo, in quanto ti guiderà verso il fare la cosa giusta. Ma è alquanto ingegnerizzato e difficile da usare.

Ricorda che tutto questo potrebbe essere ancora inutile se il DB diventa il collo di bottiglia, cosa che può facilmente essere - i database SQL sono notoriamente cattivi nel gestire aggiornamenti simultanei, e potrebbe richiedere un bel po 'di ottimizzazione per evitare blocco contesa e deadlock.

    
risposta data 28.11.2016 - 15:39
fonte
7

Iniziamo con qualche aritmetica di base.

(* 24 60 60)
86400

Ciò significa che ci sono 86400 secondi in un giorno.

(/ 100e6 86400)
1157.4074074074074

Ciò significa che per elaborare 100 milioni di record in un giorno, devi essere in grado di elaborare 1157,4 record al secondo.

Andando ancora più avanti:

(/ 1.0 1157.4074074074074)
0.000864

Ciò significa che devi essere in grado di elaborare un record, end-to-end, in 864 microsecondi.

Non importa quello che fai, questa è la verità fondamentale. Se occorrono più di 864 microsecondi per elaborare completamente un record, non sarai in grado di elaborare 100 milioni di record in 24 ore.

L'aggiunta di "threading" lo renderà peggiore, non meglio, perché aggiungi un overhead e non rimuovi nessuno dei carichi di lavoro sottostanti.

Sospetto, dopo quasi 40 anni trascorsi in questo pazzo racket, che leggere il file in memoria e scrivere i risultati sul tuo DBMS ti sta mangiando vivo.

    
risposta data 28.11.2016 - 15:12
fonte

Leggi altre domande sui tag