我对mod_wsgi的多重管理功能以及将在具有多处理能力的WSGI服务器上执行的WSGI应用程序的一般设计感到困惑。
考虑以下指令:
WSGIDaemonProcess example processes=5 threads=1
如果我理解正确,mod_wsgi将产生5个Python(例如CPython)进程,并且任何这些进程都可以接收来自用户的请求。
文档说:
共享数据需要对所有应用程序实例可见,无论它们执行哪个子进程,以及对其进行了更改 一个应用程序的数据立即可供另一个应用程序使用 包括在另一个子进程中执行的任何外部数据 必须使用诸如数据库或共享内存之类的存储。全球 普通Python模块中的变量不能用于此目的。
但是在这种情况下,当想要确保应用程序在任何WSGI条件(包括多处理条件)中运行时,它会变得非常沉重。
例如,一个包含当前连接用户数量的简单变量 - 它应该是从/向memcached读取/写入的过程安全,还是DB或(如果这样的非标准库机制是可用)共享内存?
代码会像
counter = 0
@app.route('/login')
def login():
...
counter += 1
...
@app.route('/logout')
def logout():
...
counter -= 1
...
@app.route('/show_users_count')
def show_users_count():
return counter
在多处理环境中表现不可预测?
谢谢!
答案 0 :(得分:21)
您的问题需要考虑几个方面。
首先,apache MPM和mod_wsgi应用程序之间的交互。如果以嵌入模式运行mod_wsgi应用程序(不需要WSGIDaemonProcess
,WSGIProcessGroup %{GLOBAL}
),则从apache MPM继承多处理/多线程。这应该是最快的选项,并且每个进程最终会有多个进程和多个线程,具体取决于您的MPM配置。相反,如果你在守护进程模式下使用WSGIDaemonProcess <name> [options]
和WSGIProcessGroup <name>
运行mod_wsgi,你可以很好地控制多处理/多线程,代价是overhead。
在单个apache2服务器中,您可以定义零个,一个或多个名为WSGIDaemonProcess
的es,并且每个应用程序都可以在其中一个进程中运行(WSGIProcessGroup <name>
)或以嵌入模式运行{ {1}}。
您可以通过检查WSGIProcessGroup %{GLOBAL}
和wsgi.multithread
变量来检查多处理/多线程。
使用您的配置wsgi.multiprocess
,您有5个独立的进程,每个进程都有一个执行线程:没有全局数据,没有共享内存,因为您无法控制生成子进程,但mod_wsgi正在为您执行此操作。要共享一个全局状态,您已经列出了一些可能的选项:一个数据库,您的进程接口,某种基于文件系统的持久性,一个守护程序进程(在apache之外启动)和基于套接字的IPC。
正如Roland Smith所指出的,后者可以通过multiprocessing.managers
使用高级API来实现:您创建并启动WSGIDaemonProcess example processes=5 threads=1
服务器进程的外部apache
BaseManager
并在你的应用内m = multiprocessing.managers.BaseManager(address=('', 12345), authkey='secret')
m.get_server().serve_forever()
:
connect
上面的示例是虚拟的,因为m = multiprocessing.managers.BaseManager(address=('', 12345), authkey='secret')
m.connect()
没有注册有用的方法,但是here(python docs)你会发现如何创建和代理一个对象(比如
m
。
使用counter
对您的示例进行最终评论。我知道这仅仅是一个例子,但在现实世界的应用程序中,我怀疑性能与processes=5 threads=1
相当:只有当预期性能提升超过'时,你应该进入多处理中共享数据的复杂性。单个进程许多线程的模型很重要。
答案 1 :(得分:4)
来自wsgi的进程和线程的文档:
当Apache以多个子进程的模式运行时,每个子进程将包含每个WSGI应用程序的子解释器。
这意味着在您的配置中,每个有1个线程的5个进程,将有5个解释器,没有共享数据。您的计数器对象对每个解释器都是唯一的。您需要构建一些自定义解决方案来计算会话(一个可以与之通信的常见流程,某种基于持久性的解决方案等)或者,这绝对是我的建议,使用预构建的解决方案(Google Analytics和Chartbeat是很棒的选择)。
我倾向于考虑使用全局变量来共享数据,将其作为全球滥用的一种重要形式。在我完成并行处理的大多数环境中,这是一个漏洞和可移植性问题。如果您的应用程序突然在多个虚拟机上运行,该怎么办?无论线程和进程的共享模型如何,这都会破坏您的代码。
答案 2 :(得分:2)
如果您使用multiprocessing
,则有multiple ways个进程间共享数据。 Values和Arrays仅在进程具有父/子关系(它们由继承共享)时才起作用。如果不是这种情况,请使用Manager
和Proxy
个对象。