App Engine Deferred: Rastreando las memory leaks

Tenemos una aplicación App Engine que escribe muchos archivos de un tamaño relativamente grande en Google Cloud Store. Estos archivos son CSV que se crean dinámicamente, por lo que usamos StringIO.StringIO de Python como búfer y csv.writer como la interfaz para escribir en ese búfer.

En general, nuestro proceso se ve así:

 # imports as needed # (gcs is the Google Cloud Store client) buffer = StringIO.StringIO() writer = csv.writer(buffer) # ... # write some rows # ... data = file_buffer.getdata() filename = 'someFilename.csv' try: with gcs.open(filename, content_type='text/csv', mode='w') as file_stream: file_stream.write(data) file_stream.close() except Exception, e: # handle exception finally: file_buffer.close() 

Como lo entendemos, el csv.writer no necesita estar cerrado por sí mismo. Más bien, solo el buffer arriba y el file_stream deben cerrarse.


Ejecutamos el proceso anterior en un deferred , invocado por la cola de tareas de App Engine. En última instancia, obtenemos el siguiente error después de algunas invocaciones de nuestra tarea:

Se excedió el límite de la memoria privada suave de 128 MB con 142 MB después de atender 11 solicitudes en total

    Claramente, entonces, hay una pérdida de memoria en nuestra aplicación. Sin embargo, si el código anterior es correcto (lo que admitimos puede no ser el caso), entonces nuestra única otra idea es que se está reteniendo una gran cantidad de memoria a través del servicio de nuestras solicitudes (como lo sugiere el mensaje de error).

    Por lo tanto, nos preguntamos si algunas entidades se mantienen en App Engine durante la ejecución de un deferred . También debemos tener en cuenta que nuestros CSV se escriben con éxito, a pesar de estos mensajes de error.

    Related of "App Engine Deferred: Rastreando las memory leaks"

    El síntoma descrito no es necesariamente una indicación de una pérdida de memoria de la aplicación. Las posibles explicaciones alternativas incluyen:

    • la huella de memoria de la línea base de la aplicación (que para los entornos de prueba en el lenguaje de secuencias de comandos como python puede ser más grande que la huella en el momento de inicio de la instancia, ver El uso de la memoria difiere mucho (y de manera extraña) entre el frontend y el backend ) puede ser demasiado alto para la clase de instancia configurada para la aplicación / módulo. Para corregirlo, elija una clase de instancia de memoria superior (lo que, como efecto secundario, también significa una instancia de clase más rápida). Alternativamente, si la tasa de muertes de instancias debido a exceder los límites de memoria es tolerable, simplemente deje que GAE recicle las instancias 🙂
    • Los picos de actividad, especialmente si el manejo de solicitudes de subprocesos múltiples está habilitado, significa un mayor consumo de memoria y también una sobrecarga potencial del recolector de basura de memoria. Al limitar el número de solicitudes realizadas en paralelo, agregar (mayores) demoras en el procesamiento de tareas diferidas de menor prioridad y otras medidas similares que reducen la tasa promedio de procesamiento de solicitudes por instancia puede ayudar al recolector de basura a limpiar las sobras de las solicitudes. La escalabilidad no debe ser dañada (con una escala dinámica ) ya que otras instancias se iniciarían para ayudar con el pico de actividad.

    Preguntas y respuestas relacionadas:

    • ¿Cómo gestiona la aplicación (python) la memoria en todas las solicitudes (límite de memoria privada suave excedido)
    • Uso de la memoria de consultas DB de Google App Engine
    • Pérdida de memoria en la biblioteca ndb de Google