手动停止 mod_wsgi 启动的进程,并监控 运行 启动的进程数

Manually stop processes launched by mod_wsgi, and monitor how many processes are running

know it's not recommended 到 运行 生产中的 Bottle 或 Flask 应用 python myapp.py --port=80 因为它只是一个开发服务器。

我认为不推荐使用 python myapp.py --port=5000 运行 和 link Apache 使用:RewriteEngine OnRewriteRule /(.*) http://localhost:5000/ [P,L](或者我我错了?),因为 WSGI 是首选。

所以我目前正在设置 Python app <-> mod_wsgi <-> Apache(没有 gunicorn 或其他工具来保持简单)。

问题:当使用 WSGI 时,我知道它是 Apache 和 mod_wsgi 会自动 start/stop 足够的进程 运行ning myapp.py 请求何时到来,但是:

  1. 如何手动停止这些进程?
  2. 更一般地说,有没有办法监视它们/知道有多少由 mod_wsgi 启动的进程目前仍在 运行ning?(一个原因,除其他外,是检查进程是否在请求后终止或者它们是否保持 运行ning)

示例:

我不想为此使用 service apache2 stop 因为我还 运行 其他网站 使用 Apache,而不仅仅是这个(我有一个很少 VirtualHosts)。出于同样的原因(我 运行 其他使用 Apache 的网站,一些客户端可能同时下载一个 1 GB 的文件),我不想做 service apache2 restart 这会对所有使用 Apache 的网站。

我正在寻找比 kill pid 或 SIGTERM 等更简洁的方法(因为我读到它在这种情况下是 not recommended to use signals)。

注意:我已经阅读了 ,它有所帮助,但这里是补充问题,而不是重复问题。


我当前的 Python Bottle + Apache + mod_wsgi 设置:

部分摘自 this 问题,将 display-name 添加到 WSGIDaemonProcess 以便您可以使用如下命令获取它们:

ps aux | grep modwsgi

将此添加到您的配置中:

Define GROUPNAME modwsgi
WSGIDaemonProcess yourapp user=www-data group=www-data processes=5 threads=5 display-name=%{GROUPNAME}

更新

ps 不给你 DaemonProcess display-name 的原因有几个。
如图所示 docs:

display-name=value Defines a different name to show for the daemon process when using the ps command to list processes. If the value is %{GROUP} then the name will be (wsgi:group) where group is replaced with the name of the daemon process group.

Note that only as many characters of the supplied value can be displayed as were originally taken up by argv0 of the executing process. Anything in excess of this will be truncated.

This feature may not work as described on all platforms. Typically it also requires a ps program with BSD heritage. Thus on some versions of Solaris UNIX the /usr/bin/ps program doesn’t work, but /usr/ucb/ps does. Other programs which can display this value include htop.

你可以:

设置一个display-name更小的长度:

WSGIDaemonProcess yourapp user=www-data group=www-data processes=5 threads=5 display-name=wsws

并尝试通过以下方式找到它们:

ps aux | grep wsws

或将其设置为%{GROUP}并使用守护进程组的名称(wsgi:group)进行过滤。

编辑:我的问题

中给出了更简单的WSGI配置

根据的回答,我做了一个简单的测试,确认进程还在运行ning:

Apache 配置:

<VirtualHost *:80>
  ServerName example.com
  <Directory />
    AllowOverride All
    Require all granted
  </Directory>
  WSGIScriptAlias / /home/www/wsgi_test/app.wsgi
  WSGIDaemonProcess yourapp user=www-data group=www-data processes=5 threads=5 display-name=testwsgi
</VirtualHost>

app.wsgi 文件:

import os, time
from bottle import route, template, default_app

os.chdir(os.path.dirname(__file__))

@route('/hello/<name>')
def index(name):
    global i
    i += 1
    return template('<b>Hello {{name}}</b>! request={{i}}, pid={{pid}}',
        name=name, i=i, pid=os.getpid())

i = 0
time.sleep(3)     # wait 3 seconds to make the client notice we launch a new process!

application = default_app()

现在多次访问http://www.example.com/hello/you

初始 time.sleep(3) 将有助于从客户端浏览器准确地看到 新进程何时启动 ,并且请求计数器 i 将允许查看每个进程处理了多少请求。

PID 将对应于 ps aux | grep testwsgi:

中的 PID

此外 time.sleep(3) 最多会发生 5 次(在 5 个进程中的每一个进程启动时),然后进程应该 运行 永远,直到我们 restart/stop 服务器或修改app.wsgi文件(修改它会触发5个进程的重启,你可以看到新的PID)。


[我现在将通过让我的测试 运行 来检查,并在 2 天内访问 http://www.example.com/hello/you 以查看它是否仍然是先前启动的进程或新进程!]

编辑:第二天,同样的进程仍然在运行 运行ning。现在,两天后,当重新加载相同的 URL 时,我注意到创建了新进程...(没有请求的进程会在一段时间后死亡吗?)

每个模式的 mod_wsgi 管理进程的方式在:

中进行了描述

对于嵌入式模式,您的 WSGI 应用程序 运行 在 Apache 子工作进程内部,Apache 根据 Apache MPM 设置管理创建和销毁进程的时间。由于 Apache 管理进程的方式,如果请求吞吐量不足,它们可以随时关闭,或者如果请求吞吐量增加,可以创建更多进程。当 运行ning 时,同一个进程将随着时间的推移处理许多请求,直到它被关闭。也就是说,Apache是​​动态管理进程数的。

由于这种动态进程管理,使用 mod_wsgi 的嵌入式模式不是一个好主意,除非您知道如何正确调整 Apache 以及许多其他东西。简而言之,除非您对 Apache 和 运行ning Python 应用程序有丰富的经验,否则永远不要使用嵌入式模式。您可以在以下位置观看有关为什么不想 运行 嵌入模式的视频:

还有博客post:

因此请使用守护进程模式并验证您的配置是否正确,并且您实际上正在使用守护进程模式,方法是使用签入:

对于守护程序模式,WSGI 应用程序 运行s 在一组单独的托管处理中。这些是在开始时创建的,并且将 运行 直到 Apache 重新启动,或者由于各种原因触发进程重新加载,包括:

  • 用户向守护进程发送直接关闭信号。
  • 应用程序代码向自身发送信号。
  • 修改了 WSGI 脚本文件,这将触发关闭,以便重新加载 WSGI 应用程序。
  • 由于 运行ning 请求卡住或过长,发生定义的请求超时。
  • 已达到定义的最大请求数。
  • 定义的不活动超时到期。
  • 为周期性进程重新启动定义的计时器到期。
  • 定义了启动超时,WSGI 应用程序未能在该时间内加载。

在这些情况下,当进程关闭时,它会被替换。

有关各种超时选项以及进程如何响应信号的更多详细信息,请参见:

有关 WSGI 脚本文件的源代码重新加载和触摸的更多详细信息,请参见:

记录的一个项目是如何合并代码,这些代码将查找对应用程序使用的 Python 代码文件的任何更改。当任何文件发生更改时,进程将通过向自身发送信号来重新启动。这应该只用于开发,切勿用于生产。

如果您在开发中使用 mod_wsgi-express,这比您自己手动配置 Apache 更可取,您可以使用 --reload-on-changes 选项。

如果向守护进程发送 SIGTERM 信号,则有一个设置的关闭序列,它将等待几秒钟以等待当前请求完成。如果请求没有完成,这个过程无论如何都会被关闭。该时间段由关闭超时决定。你不应该玩那个值。

如果向守护进程发送 SIGUSR1 信号,默认情况下它就像发送 SIGTERM 信号一样。但是,如果您指定关闭的正常超时,则可以延长等待当前请求完成的时间。在此期间将接受新的请求。优雅的超时也适用于其他情况,例如接收到的最大请求数,或触发周期性重启的计时器。如果您在使用 SIGUSR1 时需要超时与这些情况不同,请改为定义驱逐超时。

至于如何识别要发送信号的守护进程,使用选项WSGIDaemonProcessdisplay-name。然后使用 ps 来标识进程,或者如果它在您的平台上使用修改后的进程名称,则可能使用 killall 。如果想要更优雅地关闭,则发送 SIGUSR1 信号给守护进程,如果希望它们立即重新启动,则发送 SIGTERM 信号。

如果要跟踪守护进程 运行ning 的时间,可以使用:

import mod_wsgi
metrics = mod_wsgi.process_metrics()

metrics 值将包括调用过程的如下输出:

{'active_requests': 1,
 'cpu_system_time': 0.009999999776482582,
 'cpu_user_time': 0.05000000074505806,
 'current_time': 1525047105.710778,
 'memory_max_rss': 11767808,
 'memory_rss': 11767808,
 'pid': 4774,
 'request_busy_time': 0.001851,
 'request_count': 2,
 'request_threads': 2,
 'restart_time': 1525047096.31548,
 'running_time': 9,
 'threads': [{'request_count': 2, 'thread_id': 1},
             {'request_count': 1, 'thread_id': 2}]}

如果你只想知道有多少processes/threads用于当前守护进程组你可以使用:

mod_wsgi.process_group
mod_wsgi.application_group
mod_wsgi.maximum_processes
mod_wsgi.threads_per_process

获取有关进程组的详细信息。 daemon模式此时进程数是固定的,名字maximum_processes只是为了和embedded模式下的名字保持一致。

如果您需要运行 在进程关闭时编写代码,您不应尝试定义自己的信号处理程序。这样做,mod_wsgi 实际上会忽略它们,因为它们会干扰 Apache 和 mod_wsgi 的正常运行。相反,如果您需要 运行 进程关闭代码,请使用 atexit.register()。或者,您可以订阅由 mod_wsgi 生成的特殊事件并触发进程关闭事件。