我一直在处理一个间歇性且难以跟踪的奇怪错误。我的django网站上有一个页面允许用户下载他们购买的音乐。
问题:一些用户在下载时报告502错误。对该问题的进一步研究表明,uWSGI中存在分割错误。我真的不知道如何调试它,我正在寻找任何可能有助于找到解决方案的方法。
尝试解决问题:
我认为可能是我运行了太多的uWSGI进程,所以我降低了这一点,但由于问题只会在某些时候发生(有些用户没有问题,有些用户重试成功),我无法确定错误是否得到解决。
关于这个问题的思考:
我想这可能是由于我在这里处理文件的方式。我正在压缩的文件也被发送给其他视图中的其他用户。当uWSGI进程都试图读取文件时,这会是一个问题吗?没有进程写入文件。
下一步:
我正在寻找一些关于这方面的指导,或者关于如何获得更多关于这里发生的事情的信息的任何想法。
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
相关观点:
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)
问题发生的原因是进程未能分配一块内存。
当我第一次查看您的代码时,引起我注意的第一件事是,您正在将文件的整个内容加载到内存中,并在每次迭代时一次读取所有内容。
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()
您可能想看看这个SO关于逐块写入zipfile.ZipFile
实例的答案。