mod_wsgi错误 - 在受限模式下无法访问class.__dict__

8
这个问题在我们的生产服务器上给我们带来了很大的困扰。我们偶尔会看到这种情况(每周1次请求)。当时我们发现这是由于mod_wsgi在某些配置中做了一些奇怪的事情所致。由于我们无法跟踪此错误的原因,我们决定它不需要立即处理。
然而,今天在我们的一个生产服务器上,10%的服务器请求都出现了这个错误:
mod_wsgi (pid=1718): Target WSGI script '/installation/dir/our-program/prod-dispatch.wsgi' cannot be loaded as Python module.
mod_wsgi (pid=1718): Exception occurred processing WSGI script '/installation/dir/our-program/prod-dispatch.wsgi'.
Traceback (most recent call last):
  File "/installation/dir/our-program/prod-dispatch.wsgi", line 7, in <module>
    from pyramid.paster import get_app
  File "/installation/dir/venv/local/lib/python2.7/site-packages/pyramid-1.3a6-py2.7.egg/pyramid/paster.py", line 12, in <module>
    from pyramid.scripting import prepare
  File "/installation/dir/venv/local/lib/python2.7/site-packages/pyramid-1.3a6-py2.7.egg/pyramid/scripting.py", line 1, in <module>
    from pyramid.config import global_registries
  File "/installation/dir/venv/local/lib/python2.7/site-packages/pyramid-1.3a6-py2.7.egg/pyramid/config/__init__.py", line 61, in <module>
    from pyramid.config.assets import AssetsConfiguratorMixin
  File "/installation/dir/venv/local/lib/python2.7/site-packages/pyramid-1.3a6-py2.7.egg/pyramid/config/assets.py", line 83, in <module>
    @implementer(IPackageOverrides)
  File "/installation/dir/venv/local/lib/python2.7/site-packages/zope.interface-3.8.0-py2.7-linux-x86_64.egg/zope/interface/declarations.py", line 480, in __
    classImplements(ob, *self.interfaces)
  File "/installation/dir/venv/local/lib/python2.7/site-packages/zope.interface-3.8.0-py2.7-linux-x86_64.egg/zope/interface/declarations.py", line 445, in cl
    spec = implementedBy(cls)
  File "/installation/dir/venv/local/lib/python2.7/site-packages/zope.interface-3.8.0-py2.7-linux-x86_64.egg/zope/interface/declarations.py", line 285, in im
    spec = cls.__dict__.get('__implemented__')
RuntimeError: class.__dict__ not accessible in restricted mode

我使用的是64位的Ubuntu Precise操作系统,搭配最新版本的Apache、mod_wsgi和Python 2.7,使用mpm_worker + mod_wsgi以守护进程模式运行。此程序是服务器上唯一运行的程序,配置中只有一个wsgi解释器。这是因为mpm_worker会生成新的线程吗?更重要的是,我们该如何修复它。

我们使用以下方法将请求分成4个守护进程,基于cookie进行划分。

WSGIPythonOptimize 1

WSGIDaemonProcess sticky01 processes=1 threads=16 display-name=%{GROUP}
WSGIDaemonProcess sticky02 processes=1 threads=16 display-name=%{GROUP}
WSGIDaemonProcess sticky03 processes=1 threads=16 display-name=%{GROUP}
WSGIDaemonProcess sticky04 processes=1 threads=16 display-name=%{GROUP}

<VirtualHost *:81>
    ...
    WSGIRestrictProcess sticky01 sticky02 sticky03 sticky04
    WSGIProcessGroup %{ENV:PROCESS}
    ...

    WSGIScriptAlias / /installation/dir/our-program/prod-dispatch.wsgi        
</VirtualHost>
1个回答

10
多个子解释器与C扩展不兼容的问题已经存在很长时间了。然而,我没有意识到默认设置非常不幸。ModWSGI wiki 明确指出 WSGIApplicationGroup 指令的默认值为 %{RESOURCE},其效果将是应用程序组名称将被设置为服务器主机名和端口(如 %{SERVER} 变量所示),其中 WSGI 环境变量 SCRIPT_NAME 的值以文件分隔符分隔。这意味着,对于访问服务器时遇到的每个 Host: 标头,mod_wsgi 都会友好地生成一个新的子解释器,然后加载 C 扩展。
我无意中通过在本地服务器上使用 links 浏览器访问 localhost.invalid:81 触发了错误,导致我们的 4 个 WSGIDaemonProcesses 中的 1 个失败,无法处理所有未来的传入请求。
总之,使用mod_wsgi与金字塔或其他使用C扩展的框架时,请确保WSGIApplicationGroup始终设置为%{GLOBAL}。换句话说,使用默认设置的结果会导致你伤到自己的脚,之后你可能还想开枪打自己的头。

3
并非所有C扩展都存在问题,只有某些特定的扩展存在问题。有时候是因为C扩展中存在糟糕的编码,而另一些情况下则是因为它们在Python中使用了简化的API来处理线程状态。因此,虽然使用守护进程组并强制使用主解释器是一个好的经验法则,但并不总是必要的。 - Graham Dumpleton
好的,感谢澄清。然而,我仍然认为%{RESOURCE}默认值不太幸运,因为即使在使用http://127.0.0.1和http://localhost访问同一虚拟主机中的同一wsgi脚本时,它也会创建2个子解释器。这太神奇了。 - Antti Haapala -- Слава Україні
1
%{RESOURCE} 应该使用与其匹配的 VirtualHost 的 ServerName 值。如果没有,则说明 Apache 配置存在问题。 - Graham Dumpleton
但这不是一个NameVirtualHost,只是基于端口的,它不包含ServerName。 - Antti Haapala -- Слава Україні

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接