uWSGI和Django分段错误

时间:2015-02-22 03:07:31

标签: django segmentation-fault zip uwsgi

我一直在处理一个间歇性且难以追踪的奇怪错误。我的django支持的网站上的一个页面允许用户下载他们购买的音乐。

问题: 一些用户在下载时报告502错误。对该问题的进一步研究表明,uWSGI存在分段错误。我真的不知道如何调试这个,我正在寻找任何可能有助于找到解决方案的东西。

尝试解决问题:
我认为可能是因为我运行了太多的uWSGI进程,所以我已经降低了这个,但由于问题只是偶尔发生(有些用户没有问题,有些用户再试一次),我不能确保错误得到解决。

关于这个问题的想法:
我想这可能是由于我在这里处理文件的方式。我正在压缩的文件也被发送到其他视图中的其他用户。当uWSGI进程都试图读取文件时,它会成为一个问题吗?没有进程写入文件。

后续步骤:
我正在寻找关于此的一些指导,或者有关如何获得有关此处发生的更多信息的任何想法。

uWSGI config:

[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

相关观点:

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错误日志:

!!! 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)

1 个答案:

答案 0 :(得分:3)

问题发生的原因是你的进程无法分配一块内存。

当我第一次看你的代码时,引起我注意的第一件事是你将整个文件内容加载到内存中并在每次迭代时一次性读取它们。

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

f.read()这里将同时读取文件的全部内容并将其放入内存中,然后尝试将其写入内存的另一部分StringIO对象,最终在RAM的不同部分存储相同的数据两次

我建议您一次读取文件一行或至少合理数量的数据,并且在完成后不要忘记关闭文件用它:

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()

您可能需要查看this SO answer关于按块写入zipfile.ZipFile实例块的信息。