Il tuo problema e gli stack tecnologici sono molto simili a un progetto a cui sto lavorando come architetto di applicazioni in questo momento, quindi ti darò il mio miglior consiglio su come procedere date le informazioni e i vincoli che hai fornito.
I tuoi istinti sono corretti che la scelta migliore per questo progetto sarebbe quella di utilizzare Spring Batch o qualcosa di simile ad esso. Quello che stai facendo in modo efficace è esattamente quale sia l'elaborazione in batch e i tuoi tentativi di introdurre il multi-threading e di lavorare per evitare di esaurire la memoria durante l'elaborazione sono facilmente gestibili in Spring Batch. Dal mio punto di vista sembra che il tuo cliente abbia un'applicazione mal progettata per le funzionalità previste, e ti è stato chiesto di ripulire il caos ma non a scapito di una riscrittura.
Quindi non sto dicendo che devi usare Spring Batch ma voglio darti un po 'di contesto sul motivo per cui Spring Batch è la scelta migliore. Questo ti aiuterà a progettare il tuo approccio in modo appropriato.
Lettori, processori e scrittori
L'idea alla base dei lettori è quella di leggere in un sottoinsieme dei dati da elaborare. Questo in genere può essere fatto, tuttavia stai leggendo il file XML ora. Il tuo lettore tiene traccia di dove si trova nella posizione del file. Sta creando oggetti per il processore.
Il processore eseguirà qualsiasi logica aziendale o di integrazione che potresti avere.
Il writer può utilizzare uno strumento come Hibernate per scrivere singoli record sul database relazionale.
Chunking e transazioni
Una porzione di dati è solo un sottoinsieme di oggetti dati letti, elaborati e scritti in un'unica transazione contigua. Se la transazione viene completata fino in fondo, è chiaro che è possibile eseguire il commit nel database. Nell'eventualità di un'eccezione, è necessario definire il comportamento dell'eccezione nel punto in cui si esegue il rollback della transazione a livello di database e si registra correttamente quale blocco di record non è stato completato correttamente. Forse, come parte di questo comportamento di rollback, si desidera includere un comportamento degli eventi di notifica per inviare un'email a un gruppo di supporto per esaminare il problema. Utilizzare il framework delle transazioni tramite Spring + JTA è l'approccio migliore.
Realisticamente però non puoi avere una discussione su cosa fare quando c'è un'eccezione senza considerare i tuoi requisiti di business (o come sospetto, forse la mancanza di requisiti di business da parte del tuo cliente qui). La definizione di ciò che accade quando alcuni record non vengono elaborati non è qualcosa che possiamo dirti, è qualcosa che deve essere affrontato nei tuoi requisiti aziendali, oppure è un vuoto.
Indipendentemente dal modo in cui ti avvicini a cosa fare nel tuo comportamento di rollback, 1 GB di dati per un singolo file è troppo per una singola transazione e sarebbe inutile buttar via tutta l'elaborazione che è stata inserita in quel file a causa di ciò che potrebbe ammonta a un carattere imprevisto in alcuni record arbitrari.
- Vuoi ridurre i dati di input a una dimensione ragionevole in modo tale che sia disponibile memoria sufficiente per tutti i file attualmente in elaborazione allo stesso tempo.
- Vuoi che il tuo blocco venga singolarmente trasformato in modo tale che una volta completato non dovrai più rivedere questi record
- Si desidera elaborare questi file un blocco alla volta all'inizio e solo dopo aver raggiunto le metriche prestazionali desiderate se si considera un approccio multi-thread o distribuito.
- Si desidera registrare quale frammento si sta attualmente elaborando nel database in una sorta di tabella di metadati e, se un blocco non riesce, nel comportamento di rollback delle eccezioni si desidera aggiornare nel database il chunk non è riuscito nel processo.
- Se un blocco non riesce su un file, è necessario interrompere completamente l'elaborazione fino a quando il problema non viene identificato e risolto. Potrebbe trattarsi di un coinvolgimento umano, quindi è probabilmente necessario prendere in considerazione una funzionalità di supporto per riavviare un lavoro fallito nel punto in cui era stato interrotto.
Prestazioni e ridimensionamento
Questo mi è di grande aiuto in quanto non so da dove provenga il file, come viene invocato il processo di elaborazione file e quali sono i requisiti non funzionali relativi alle prestazioni. Il mio consiglio qui ovviamente è che la scommessa sicura è quella di elaborare come singole transazioni in un unico thread per iniziare. Il multi-threading o addirittura l'introduzione dell'elaborazione parallela e del calcolo distribuito qui potrebbero essere potenzialmente molto complicati se si sta tentando di eseguire il rollover. Framework come Spring Batch ti aiutano a gestirlo se ne hai bisogno, ma ci sono buone probabilità che non lo farai se il client non offrisse severi requisiti di performance. Le tue preoccupazioni circa il deadlocking del database e il mantenimento dei vincoli di memoria sul tuo server sono alleviati gestendole in un unico thread.