![在预分叉+线程模式下定义多个挂载点时,uWSGI 会引发段错误](https://linux22.com/image/640330/%E5%9C%A8%E9%A2%84%E5%88%86%E5%8F%89%2B%E7%BA%BF%E7%A8%8B%E6%A8%A1%E5%BC%8F%E4%B8%8B%E5%AE%9A%E4%B9%89%E5%A4%9A%E4%B8%AA%E6%8C%82%E8%BD%BD%E7%82%B9%E6%97%B6%EF%BC%8CuWSGI%20%E4%BC%9A%E5%BC%95%E5%8F%91%E6%AE%B5%E9%94%99%E8%AF%AF.png)
我正在托管一个由多个 Python 模块组成的应用程序。到目前为止,我们在 MPM 工作模式下使用 Apache,并使用 mod_wsgi 作为工作环境。
现在我们想检查 nginx + uwsgi 是否可能是性能更高的环境。Python 是 Python 2.6.6,uwsgi 是 2.0.7。我的应用程序有以下 uWSGI 配置(简化示例):
[uwsgi]
chdir = /path/to/app
chmod-socket = 777
no-default-app = True
socket = /tmp/socket.sock
master = 1
processes = 4
threads = 2
enable-threads = true
touch-reload=/root/uwsgi.ini
manage-script-name = True
mount = /accounts=account.py
[... several more mount directives ...]
mount = /ping=ping.py
[... several more mount directives ...]
mount = /subscriptions=subscription.py
callable = application
enable-logging = 1
plugin = /usr/lib/uwsgi/stats_pusher_statsd
stats-push = statsd:graphite-int.cern.ch:8125:uwsgi-test
enable-metrics = 1
memory-report = 1
stats = /tmp/stats.sock
当我像这样启动 uWSGI 时,一开始一切都看起来很好:
[uWSGI] getting INI configuration from rucio.wsgi.ini
*** Starting uWSGI 2.0.7 (64bit) on [Mon Aug 25 19:15:07 2014] ***
compiled with version: 4.4.7 20120313 (Red Hat 4.4.7-4) on 22 August 2014 22:51:22
os: Linux-2.6.32-431.3.1.el6.x86_64 #1 SMP Mon Jan 6 11:34:51 CET 2014
nodename: rucio-server-dev-ngnix
machine: x86_64
clock source: unix
detected number of CPU cores: 4
current working directory: /root
detected binary path: /usr/bin/uwsgi
!!! no internal routing support, rebuild with pcre support !!!
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
your processes number limit is 63837
your memory page size is 4096 bytes
detected max file descriptor number: 4096
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 inherited UNIX address /tmp/rucio.sock fd 3
Python version: 2.6.6 (r266:84292, Jan 23 2014, 10:39:35) [GCC 4.4.7 20120313 (Red Hat 4.4.7-4)]
Python main interpreter initialized at 0x26b1c00
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 415360 bytes (405 KB) for 8 cores
*** Operational MODE: preforking+threaded ***
initialized 108 metrics
mounting account.py on /accounts
WSGI app 0 (mountpoint='/accounts') ready in 1 seconds on interpreter 0x26b1c00 pid: 2839
[... several more mount outputs like the one above ...]
mounting ping.py on /ping
WSGI app 8 (mountpoint='/ping') ready in 2 seconds on interpreter 0x9b020b0 pid: 2839
[... several more mount outputs like the one above ...]
mounting trace.py on /traces
WSGI app 15 (mountpoint='/traces') ready in 2 seconds on interpreter 0xf393210 pid: 2839
*** uWSGI is running in multiple interpreter mode ***
gracefully (RE)spawned uWSGI master process (pid: 2839)
spawned uWSGI worker 1 (pid: 2986, cores: 2)
spawned uWSGI worker 2 (pid: 2988, cores: 2)
spawned uWSGI worker 3 (pid: 2990, cores: 2)
spawned uWSGI worker 4 (pid: 2992, cores: 2)
metrics collector thread started
*** Stats server enabled on /tmp/rucio-stats.sock fd: 16 ***
但是,当第一个请求到达时,无论请求的挂载点是什么,我都会收到以下回溯(例如 GET /ping):
!!! uWSGI process 2988 got Segmentation Fault !!!
*** backtrace of 2988 ***
/usr/bin/uwsgi(uwsgi_backtrace+0x29) [0x46c8d9]
/usr/bin/uwsgi(uwsgi_segfault+0x21) [0x46ca61]
/lib64/libc.so.6() [0x38bf8329a0]
/usr/lib64/libpython2.6.so.1.0(PyObject_Call+0x3a) [0x38c2c43c4a]
/usr/lib64/libpython2.6.so.1.0(PyEval_CallObjectWithKeywords+0x43) [0x38c2ccfc93]
/usr/bin/uwsgi(python_call+0x1f) [0x47a0bf]
/usr/bin/uwsgi(uwsgi_request_wsgi+0x132) [0x47c602]
/usr/bin/uwsgi(wsgi_req_recv+0x92) [0x420352]
/usr/bin/uwsgi(simple_loop_run+0xc5) [0x464265]
/usr/bin/uwsgi(uwsgi_ignition+0x254) [0x468074]
/usr/bin/uwsgi(uwsgi_worker_run+0x330) [0x468400]
/usr/bin/uwsgi(uwsgi_run+0x3e5) [0x468865]
/lib64/libc.so.6(__libc_start_main+0xfd) [0x38bf81ed1d]
/usr/bin/uwsgi() [0x41d189]
*** end of backtrace ***
DAMN ! worker 2 (pid: 2988) died :( trying respawn ...
Respawned uWSGI worker 2 (new pid: 3003)
我猜最有趣的部分是,如果我删除所有其他挂载点,例如只保留
mount = /ping=ping.py
一切按预期运行。为了确保此错误与我们的应用程序无关,我还尝试了 uWSGI 站点上提供的“Hello World”示例。但行为保持不变。一个挂载点运行正常,但只要有一个挂载点就会导致此段错误。
此外,只要我删除线程设置threads = 2(不是启用线程!),它也可以很好地处理多个挂载点。因此,我怀疑错误实际上仅限于在多线程模式下有多个挂载点。请记住,它在Apache MPM工作模式下工作,所以我不认为应用程序是原因(至少在这种情况下不是:D)
真的很想弄清楚这一点,因为如果只有 Apache 具有多线程功能,那么 Apache 节点和 nginx/uwsgi 节点之间的比较就不公平,对吗?
如果您需要更多信息,请告诉我,我会很乐意为您提供。感谢您提供的任何提示或想法,只要读到这里,您就已经是每日论坛英雄了 ;-)
干杯,拉尔夫
答案1
尝试这个补丁
但在采用这种方法之前请三思。在同一个进程地址空间中拥有多个应用程序可能看起来很酷,但迟早你会为次优的实现付出代价(在 CPython 中使用多个线程和多个解释器时有太多极端情况和变通方法)
如果它在 mod_wsgi 中运行良好,那么很可能也能在 uWSGI 中运行,但请考虑在专用进程中拆分每个挂载点。