手动停止mod_wsgi启动的进程,并监视正在运行的进程数

时间:2018-04-22 09:42:02

标签: python apache mod-wsgi wsgi bottle

know it's not recommended使用python myapp.py --port=80在制作时运行Bottle或Flask应用,因为它只是一个开发服务器。

我认为不建议使用python myapp.py --port=5000运行它并将其链接到Apache:RewriteEngine OnRewriteRule /(.*) http://localhost:5000/$1 [P,L](或者我错了?),因为WSGI是首选。

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

问题:在使用WSGI时,我知道Apache和mod_wsgi会在请求到来时自动启动/停止运行myapp.py的足够进程,但是:

  1. 如何手动停止这些流程?
  2. 更一般地说,有没有办法监控它们/知道mod_wsgi启动的进程当前还在运行多少?(其中一个原因是检查进程是否在请求后终止或者如果他们继续跑步)
  3. 示例:

    • 我在myapp.py中进行了一些更改,我想重新启动运行它的所有进程,这些进程已由mod_wsgi启动(注意:我知道mod_wsgi可以查看源代码的更改,然后重新启动,但这仅适用于.wsgi文件上的更改,而不是.py文件。我已经读过touch myapp.wsgi可以解决这个问题,但更常见的是我喜欢能够手动停止和重启

    • 我想暂时停止整个应用myapp.py(所有实例)

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

    我正在寻找一种比kill pid或SIGTERM等更清晰的方法(因为在这种情况下我读了not recommended to use signals)。

    注意:我已经阅读了How to do graceful application shutdown from mod_wsgi,它有所帮助,但这里是补充问题,而不是重复问题。

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

    • 安装:

      apt-get install libapache2-mod-wsgi
      a2enmod wsgi      # might be done automatically by previous line, but just to be sure
      
    • Apache配置(来源:Bottle doc):

      <VirtualHost *:80>
        ServerName example.com
        WSGIDaemonProcess yourapp user=www-data group=www-data processes=5 threads=5
        WSGIScriptAlias / /home/www/wsgi_test/app.wsgi
        <Directory /home/www/wsgi_test>
          WSGIProcessGroup yourapp
          WSGIApplicationGroup %{GLOBAL}
          Require all granted
        </Directory>
      </VirtualHost>
      

      最多应该有5个进程,是吗?正如之前在问题中所述,如何知道有多少人正在运行,如何阻止他们?

    • /home/www/wsgi_test/app.wsgi(来源:Bottle doc

      import os
      from bottle import route, template, default_app
      
      os.chdir(os.path.dirname(__file__))
      
      @route('/hello/<name>')
      def index(name):
          return template('<b>Hello {{name}}</b>!', name=name)
      
      application = default_app()
      

3 个答案:

答案 0 :(得分:2)

部分取自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-namedocs

所示
  

display-name = value定义要为守护程序显示的其他名称   使用ps命令列出进程时的进程。如果值是   %{GROUP}然后名称将是(wsgi:group),其中组被替换   使用守护程序进程组的名称。

     

请注意,只提供所提供值的字符数   显示为最初由执行的argv0占用   处理。任何超出此范围的内容都将被截断。

     

此功能可能无法在所有平台上执行。通常它   还需要一个具有BSD传统的ps程序。因此在某些版本上   Solaris UNIX / usr / bin / ps程序不起作用,但/ usr / ucb / ps   确实。其他可以显示此值的程序包括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)的名称进行过滤。

答案 1 :(得分:2)

在每种模式下使用mod_wsgi管理进程的方式如下所述:

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

由于这种动态的流程管理,使用mod_wsgi的嵌入模式是个坏主意,除非你知道如何正确地调整Apache以及许多其他事情。简而言之,除非您对Apache有丰富的经验并使用它运行Python应用程序,否则永远不要使用嵌入式模式。您可以观看有关您不希望在嵌入模式下运行的原因的视频:

还有博客文章:

因此,请使用守护程序模式并验证您的配置是否正确,并且您实际上是通过使用签入来使用守护程序模式:

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

  • 守护进程发送一个直接信号,由用户关闭。
  • 应用程序的代码向自己发送信号。
  • 修改了WSGI脚本文件,该文件将触发关闭,以便重新加载WSGI应用程序。
  • 由于卡住或长时间运行请求而导致定义的请求超时。
  • 已定义的最大请求数。
  • 定义的不活动超时到期。
  • 定期进程重启的定义计时器到期。
  • 定义了启动超时,并且在那段时间内无法加载WSGI应用程序。

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

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

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

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

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

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

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

关于如何识别要发送信号的守护程序进程,请使用选项display-name的{​​{1}}。然后使用WSGIDaemonProcess标识进程,或者如果它在您的平台上使用修改后的进程名称,则可以使用ps。如果想要更优雅的关闭,则发送守护进程处理killall信号;如果希望它们立即重新启动,则发送SIGUSR1

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

SIGTERM

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}]}

获取有关进程组的详细信息。此时对于守护程序模式的进程数是固定的,名称mod_wsgi.process_group mod_wsgi.application_group mod_wsgi.maximum_processes mod_wsgi.threads_per_process 只是与嵌入模式下的名称一致。

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

答案 2 :(得分:1)

根据Evhz的回答,我做了一个简单的测试来检查进程是否仍在运行:

Apache配置:

<VirtualHost *:80>
  ServerName example.com
  WSGIDaemonProcess yourapp user=www-data group=www-data processes=5 threads=5 display-name=testwsgi
  WSGIScriptAlias / /home/www/wsgi_test/app.wsgi
  <Directory /home/www/wsgi_test>
    WSGIProcessGroup yourapp
    WSGIApplicationGroup %{GLOBAL}
    Require all granted
  </Directory>
</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中的值相对应:

enter image description here

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

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

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