django segmentation-fault zip uwsgi

uWSGI y Django falla de segmentación



segmentation-fault zip (1)

He estado lidiando con un error extraño que es intermitente y difícil de rastrear. Una de las páginas de mi sitio django permite a los usuarios descargar música que han comprado.

El problema: algunos usuarios informan sobre un error 502 al momento de la descarga. Una investigación adicional del problema muestra que hay una falla de segmentación en uWSGI. Realmente no sé cómo depurar esto, y estoy buscando cualquier cosa que pueda ayudar a encontrar una resolución.

Intenta resolver el problema:
Pensé que podría ser porque estaba ejecutando demasiados procesos uWSGI, así que lo he bajado, pero dado que el problema solo ocurre a veces (algunos usuarios no tienen problemas, algunos lo intentan de nuevo con éxito), no puedo estar seguro del error. esta resuelto.

Pensamientos sobre el tema:
Estoy pensando que podría ser debido a la forma en que estoy manejando los archivos aquí. Los archivos que estoy comprimiendo también se envían a otros usuarios en otras vistas. ¿Podría ser un problema cuando los procesos de uWSGI están tratando de leer un archivo? Ningún proceso escribe en los archivos.

Próximos pasos:
Estoy buscando alguna orientación sobre esto, o cualquier idea sobre cómo puedo obtener un poco más de información sobre lo que está sucediendo aquí.

configuración uWSGI:

[uwsgi] plugin=/etc/uwsgi/python_plugin.so wsgi-file = /path/to/my/project/projectname/wsgi.py home = /path/to/my/project/ master = true socket = /tmp/uwsgi.sock chmod-socket = 666 vacuum = true processes = 3 workers = 15 min-worker-lifetime = 45 max-requests = 100 reload-mercy = 5 harakiri = 20 buffer-size = 16384

Vista relevante:

def zipForDownload(album): bonus = BonusContent.objects.filter(album=album) bonus_files = [open(f.bonus_file.path, ''rb'') for f in bonus] tracks = trackSort(list(Track.objects.filter(album=album))) track_files = [open(f.audio_file.path, ''rb'') for f in tracks] zipped_file = StringIO.StringIO() with zipfile.ZipFile(zipped_file, ''w'') as zip: for i, f in enumerate(track_files): f.seek(0) num = tracks[i].track_number name = tracks[i].name ext = os.path.basename(f.name).split(''.'')[-1] zip.writestr("{0} - {1}.{2}".format(num, name, ext), f.read()) for i, f in enumerate(bonus_files): name = bonus[i].name ext = os.path.basename(f.name).split(''.'')[-1] zip.writestr("{0}.{1}".format(name, ext), f.read()) zipped_file.seek(0) response = HttpResponse(zipped_file, content_type=''application/octet-stream'') response[''Content-Disposition''] = ''attachment; filename=%s.zip'' % (album.name) return response def downloadPostPin(request, purchase): if request.POST.get(''PIN'').encode(''utf-8'') == purchase.download_pin.encode(''utf-8''): # Get zip response with all tracks and bonus content resp = zipForDownload(purchase.album) return resp else: # Otherwise, return the same page again with an error error = "Invalid PIN. Please try again!" return downloadPrePin(request, purchase, error)

UWSGI error log:

!!! uWSGI process 8094 got Segmentation Fault !!! *** backtrace of 8094 *** /home/web/.envs/music/bin/uwsgi(uwsgi_backtrace+0x2e) [0x46a1be] /home/web/.envs/music/bin/uwsgi(uwsgi_segfault+0x21) [0x46a581] /lib/x86_64-linux-gnu/libc.so.6(+0x36c30) [0x7fdc1ffd6c30] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Malloc+0x248) [0x7fdc206ef508] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyString_FromStringAndSize+0xa2) [0x7fdc206de232] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x3be7) [0x7fdc206fe0e7] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x80d) [0x7fdc2070117d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x48d8) [0x7fdc206fedd8] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x80d) [0x7fdc2070117d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x162310) [0x7fdc20701310] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x7d30d) [0x7fdc2061c30d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_CallObjectWithKeywords+0x47) [0x7fdc20687837] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0xff706) [0x7fdc2069e706] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x2920) [0x7fdc206fce20] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x161883) [0x7fdc20700883] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x1a7d02) [0x7fdc20746d02] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PySequence_List+0x2c) [0x7fdc207471bc] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PySequence_Fast+0x3d) [0x7fdc2074807d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x1aa995) [0x7fdc20749995] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x4abc) [0x7fdc206fefbc] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x80d) [0x7fdc2070117d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x162310) [0x7fdc20701310] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_CallFunction+0xbb) [0x7fdc20706efb] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x16a15d) [0x7fdc2070915d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(_PyObject_GenericSetAttrWithDict+0x107) [0x7fdc205f00b7] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_SetAttr+0x8f) [0x7fdc206aeadf] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x1cda) [0x7fdc206fc1da] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x80d) [0x7fdc2070117d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x1623e5) [0x7fdc207013e5] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x7d30d) [0x7fdc2061c30d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x12e48f) [0x7fdc206cd48f] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x12c4df) [0x7fdc206cb4df] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x2316) [0x7fdc206fc816] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x4b59) [0x7fdc206ff059] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x4b59) [0x7fdc206ff059] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x80d) [0x7fdc2070117d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x1623e5) [0x7fdc207013e5] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0xeb1) [0x7fdc206fb3b1] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x80d) [0x7fdc2070117d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x48d8) [0x7fdc206fedd8] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x80d) [0x7fdc2070117d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x162310) [0x7fdc20701310] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x7d30d) [0x7fdc2061c30d] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(+0x12e5f5) [0x7fdc206cd5f5] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyObject_Call+0x43) [0x7fdc206c8e23] /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_CallObjectWithKeywords+0x47) [0x7fdc20687837] /home/web/.envs/music/bin/uwsgi(python_call+0x11) [0x4808a1] /home/web/.envs/music/bin/uwsgi(uwsgi_request_wsgi+0x116) [0x482a96] /home/web/.envs/music/bin/uwsgi(wsgi_req_recv+0xa2) [0x41f1f2] /home/web/.envs/music/bin/uwsgi(simple_loop_run+0xc4) [0x466664] /home/web/.envs/music/bin/uwsgi(uwsgi_ignition+0x194) [0x46a7d4] /home/web/.envs/music/bin/uwsgi(uwsgi_worker_run+0x2dd) [0x46f02d] /home/web/.envs/music/bin/uwsgi(uwsgi_run+0x3b4) [0x46f554] /home/web/.envs/music/bin/uwsgi(_start+0) [0x41e8ae] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fdc1ffc1ec5] *** end of backtrace *** DAMN ! worker 9 (pid: 8094) died :( trying respawn ... Respawned uWSGI worker 9 (new pid: 8371)


El problema ocurre porque su proceso no asigna un trozo de memoria.

Cuando miro por primera vez su código, lo primero que me llamó la atención fue que está cargando todo el contenido del archivo en la memoria y que los lee todos a la vez en cada iteración.

zip.writestr("{0} - {1}.{2}".format(num, name, ext), f.read())

f.read() aquí leerá todo el contenido del archivo a la vez y lo pondrá en la memoria, luego intentará escribirlo en otra sección de la memoria, el objeto StringIO , que a su vez terminará almacenando los mismos datos dos veces en diferentes partes de la RAM

Le recomendaría leer el archivo de una línea a la vez o al menos una cantidad de datos razonable y no olvide cerrar el archivo cuando haya terminado con él:

for i, f in enumerate(track_files): f.seek(0) ... while True: data = f.read(2**16) if not data: break else: zip.write(data) ... f.close()

Es posible que desee echar un vistazo a esta respuesta SO sobre la escritura en un zipfile.ZipFile por fragmento.