Uso alto de memoria en script de importación

Estoy intentando realizar una prueba de importación desde nuestro tablero existente. Tenemos aproximadamente 25 millones de publicaciones para importar (publicaciones normales + conversaciones privadas), por lo que, para acelerar el proceso, he creado varias copias del script de importación para ejecutarlas simultáneamente y dividir la carga de temas. Esto funcionó bien durante un par de días, pero con el tiempo noté que el uso de memoria de cada proceso aumentaba lentamente hasta llegar a unos 2 GB cada uno. Luego, el servidor finalmente se quedó sin memoria y mató la base de datos MySQL de origen alrededor del punto de los 16 millones de publicaciones.

He aumentado la memoria del sistema de 24 GB a 32 GB, pero ahora, cuando intento reiniciar incluso un proceso de importación y continuar desde donde se quedó, ese proceso consume alrededor de 10 GB de memoria desde el inicio, antes de comenzar a importar publicaciones. Antes podía ejecutar 8 procesos de importación simultáneos, pero ahora solo puedo ajustar 2 en un pool de memoria más grande. ¿Por qué existe esta gran discrepancia entre el uso de memoria en una instalación limpia y el uso de memoria al reiniciar una importación después de un fallo? ¿Hay alguna forma de reducir esta huella de memoria para poder acelerar nuevamente el proceso de importación? Un servidor con 128 GB - 256 GB de memoria será prohibitivamente caro (y no será necesario después de la importación), y ejecutar solo 2 procesos de importación significará que la importación tardará semanas en completarse.

Eso suena como una expresión regular atrapada en un bucle o algo así. Imprime mensajes de depuración y omite la fila problemática para la importación.

El uso de memoria parece ocurrir completamente durante las secciones de “Cargando publicaciones existentes…” (o temas) del inicio del script de importación, no durante el procesamiento real de las publicaciones. Por lo que puedo ver, esa sección extrae información de publicaciones y temas de la base de datos y no debería involucrar ninguna expresión regular.

Las variables @posts y @topics parecen usarse para cosas como el método “topic_lookup_from_imported_post_id”. Esto tiene sentido, excepto que cuando el script se ejecutaba inicialmente, el uso de memoria nunca se acercaba a lo que estoy viendo ahora, y sin embargo, esos métodos siguen funcionando.

¿Ya revisaste los scripts de importación masiva? Podrían tener un menor consumo de memoria.

Pero es cierto que los scripts de importación mantienen en memoria un mapa de los IDs antiguos de usuario, tema y publicación hacia los nuevos, lo que requiere bastante RAM, especialmente si quieres varias copias.

¿Entiendes que después de ejecutar la importación inicial, la volverás a ejecutar para importar solo los datos nuevos y será mucho más rápida, verdad? Así que, después de esperar un mes para hacer la importación inicial, la última no tardará tanto.

No tengo conocimiento de ningún script de importación masiva. ¿Están en algún lugar del directorio import_scripts?

Sí, ahí es donde tengo problemas. Las cosas iban relativamente bien durante la importación inicial, ejecutando 8 procesos de importación, hasta que el sistema se quedó sin memoria. Ahora, cuando intento reiniciar el proceso de importación y reanudar donde se quedó, cada proceso está utilizando aproximadamente 5 veces más memoria que cuando se bloqueó por primera vez.

Necesitamos completar una importación total para tener una prueba adecuada y establecer expectativas sobre cuándo podría ocurrir esta migración en la realidad. Por ahora, todavía no tengo una comprensión clara de qué esperar en cuanto a aspectos como el rendimiento. Además, he notado que incluso en el hito de 16 millones de publicaciones, el tamaño de la base de datos ya es más del 50 % mayor que nuestra base de datos actual; eso es una sorpresa. El largo tiempo de importación no hace que esto sea imposible, pero sin duda sería mucho más conveniente si la expectativa se planteara en días en lugar de semanas.

Consulte discourse/script/bulk_import at main · discourse/discourse · GitHub.

En cuanto a los temas y las publicaciones, en realidad no es factible ejecutar importaciones en paralelo, ya que no se puede importar una publicación en un tema si el tema y todas las publicaciones anteriores no han sido importados previamente. Supongo que podrías tener procesos paralelos para usuarios y temas, pero no para publicaciones, a menos que reescribas el script para cargar todas las publicaciones de un tema, lo que permitiría importaciones en paralelo; eso es definitivamente viable, pero no es la forma en que funciona ninguno de los scripts que he utilizado. Sin embargo, aún tendrás el problema de que mantengan en la memoria RAM un mapa de IDs de antiguo a nuevo.

Importar 25 millones de publicaciones no es conveniente. :slight_smile:

Esto es lo que estoy haciendo. He dividido los temas de modo que cada uno sea manejado por un solo proceso. No es una división perfecta, pero es varias veces más rápido que un proceso lineal único.

Esta es la parte más confusa. Asumo que lo está haciendo a medida que avanza, y por eso vi que el uso de memoria de cada proceso aumentó durante 3 días. Estaban llegando a alrededor de 2 - 2,5 GB de memoria cada uno antes de que se perdiera la conexión a la base de datos.

¿Cada proceso solo estaría manteniendo el mapa para las publicaciones que ha importado? Si ese es el caso, entonces podría tener sentido que el uso de memoria se haya disparado después de reiniciar la importación.

Creo que sí. Y los demás no funcionarán correctamente porque no tienen esos días que fueron importados por otros procesos. No creo que lo que estás haciendo funcione.

Tendrás que revisar los scripts de importación masiva o reescribir base.rb para mantener un seguimiento de los enlaces a los IDs de importación de otra manera.

Es muy probable que pases más semanas depurando tu código que simplemente esperando. La velocidad del procesador en un solo proceso es la mejor manera de acelerar las cosas.

Hasta ahora no he visto ningún problema con este enfoque, aunque podría haber algunos problemas con algunos de los métodos que se ejecutan después de la importación de publicaciones. Probablemente querré asegurarme de que todo se detenga después de eso y luego ejecutar una ejecución de un solo hilo para garantizar que el resto se maneje correctamente.

Dicho esto, tu sugerencia de manejar los enlaces de ID de importación de manera diferente probablemente sea buena en cualquier caso. Mantener una cantidad arbitrariamente grande de datos en algunas variables durante la duración del script no es muy eficiente.