Sto cercando di eseguire un test di importazione dal nostro forum esistente. Abbiamo circa 25 milioni di post da importare (post normali + conversazioni private), quindi per accelerare il processo ho creato diverse copie dello script di importazione da eseguire simultaneamente, suddividendo il carico dei topic. Tutto funzionava bene per un paio di giorni, ma col tempo ho notato che l’utilizzo della memoria per ogni processo aumentava lentamente fino a circa 2 GB ciascuno. Alla fine, il server ha esaurito la memoria e ha terminato il processo del database MySQL sorgente intorno al milione di post 16.
Ho aumentato la memoria di sistema da 24 GB a 32 GB, ma ora, quando provo a riavviare anche solo un processo di importazione e riprendere da dove si era interrotto, quel processo consuma circa 10 GB di memoria già all’avvio, prima ancora di iniziare l’importazione dei post. Prima potevo eseguire 8 processi di importazione simultanei, ora riesco a farne entrare solo 2 in un pool di memoria più grande. Perché c’è questa enorme differenza tra l’utilizzo della memoria in un’installazione pulita e quello quando si riavvia un import dopo un fallimento? Esiste un modo per ridurre questo footprint di memoria così da poter accelerare nuovamente il processo di importazione? Un server con 128 GB - 256 GB di memoria sarebbe proibitivamente costoso (e non necessario dopo l’importazione), e lavorare con soli 2 processi di importazione significherebbe che l’importazione richiederà settimane per completarsi.
Sembra un’espressione regolare bloccata in un ciclo o qualcosa del genere. Stampa messaggi di debug e ignora la riga problematica durante l’importazione.
L’utilizzo della memoria sembra verificarsi interamente durante le sezioni “Caricamento dei post esistenti…” (o degli argomenti) all’avvio dello script di importazione, non durante l’effettiva elaborazione dei post. Da quanto posso vedere, quella sezione recupera le informazioni sui post e sugli argomenti dal database e non dovrebbe essere coinvolta alcuna espressione regolare.
Le variabili @posts e @topics sembrano essere utilizzate per cose come il metodo “topic_lookup_from_imported_post_id”. Questo ha senso, tranne per il fatto che quando lo script era nella fase iniziale, l’utilizzo della memoria non si è mai avvicinato a quanto vedo ora, eppure quei metodi funzionano ancora.
Hai guardato gli script di importazione in blocco? Potrebbero avere un footprint di memoria più piccolo.
Ma è vero che gli script di importazione mantengono in memoria una mappa degli ID vecchi di utente, argomento e post verso quelli nuovi, quindi occupano parecchia RAM, specialmente se vuoi più copie.
Capisci che dopo aver eseguito l’importazione iniziale, la eseguirai di nuovo per importare solo i nuovi dati e sarà molto più veloce, vero? Quindi dopo aver aspettato un mese per l’importazione iniziale, quella finale non richiederà molto tempo.
Non sono a conoscenza di script di importazione in blocco. Si trovano forse nella directory import_scripts?
Sì, è proprio qui che incontro difficoltà. Durante l’importazione iniziale, con 8 processi di importazione in esecuzione, tutto procedeva relativamente bene fino a quando il sistema non ha esaurito la memoria. Ora, quando provo a riavviare il processo di importazione e riprendere da dove si era interrotto, ogni processo utilizza circa 5 volte la memoria che impiegava al momento del primo crash.
Dobbiamo completare un’importazione completa per effettuare un test adeguato e stabilire le aspettative su quando questa migrazione potrà avvenire realmente. Al momento non ho ancora una chiara comprensione di cosa aspettarmi per quanto riguarda aspetti come le prestazioni. Ho anche notato che, già al traguardo dei 16 milioni di post, le dimensioni del database sono superiori di oltre il 50% rispetto al nostro database attuale: è una sorpresa. Il lungo tempo di importazione non rende impossibile completare l’operazione, ma sarebbe certamente molto più comodo se le aspettative fossero espresse in giorni invece che in settimane.
Per i topic e i post, non è realmente fattibile eseguire importazioni parallele, poiché non è possibile importare un post in un topic se il topic e tutti i post precedenti non sono già stati importati. Immagino che si potrebbero avere processi paralleli per utenti e topic, ma non per i post, a meno di riscrivere lo script per recuperare tutti i post di un topic, il che permetterebbe importazioni parallele; è certamente fattibile, ma non è così che funzionano gli script che ho utilizzato. Tuttavia, avrai ancora il problema di mantenere in RAM una mappa degli ID da vecchio a nuovo.
È esattamente quello che sto facendo. Ho suddiviso gli argomenti in modo che ciascuno sia gestito da un solo processo. La suddivisione non è perfetta, ma è diverse volte più veloce di un unico processo lineare.
Questa è la parte più confusa. Presumo che lo stia facendo man mano che procede, ed è per questo che ho visto l’utilizzo della memoria per ogni processo aumentare nell’arco di 3 giorni. Erano arrivati a consumare circa 2 - 2,5 GB di memoria ciascuno prima che la connessione al database andasse persa.
Ogni processo mantiene la mappa solo per i post che ha importato? Se è così, potrebbe spiegare perché l’utilizzo della memoria è esploso dopo il riavvio dell’importazione.
Penso di sì. E gli altri non funzioneranno correttamente perché non dispongono di quei giorni importati da altri processi. Non credo che ciò che stai facendo funzionerà.
Dovrai o esaminare gli script di importazione in blocco o riscrivere base.rb per tenere traccia dei link agli ID di importazione in un altro modo.
È probabile che tu passerai più settimane a correggere il tuo codice che ad aspettare. La velocità della CPU a processo singolo è il modo migliore per accelerare le cose.
Finora non ho riscontrato problemi con questo approccio, anche se potrei immaginare che alcuni problemi si verifichino con alcuni dei metodi eseguiti dopo l’importazione del post. Probabilmente vorrò assicurarmi che tutto si fermi dopo di ciò e poi eseguire un’esecuzione single-threaded per garantire che il resto venga gestito correttamente.
Detto questo, la tua suggerimento di gestire i link degli ID di importazione in modo diverso è probabilmente una buona idea in ogni caso. Mantenere una quantità arbitrariamente grande di dati in alcune variabili per la durata dello script non è molto efficiente.