Django的AppConfig.ready()似乎在Apache wsgi中每个线程被调用一次

时间:2019-09-16 06:13:17

标签: python django multithreading apache mod-wsgi

我在apps.py中有以下代码:

class Pqawv1Config(AppConfig):
    # ...
    def ready(self):
        env_run_main=os.environ.get('RUN_MAIN')
        print('IS_PRODUCTION=%s, RUN_MAIN=%s' % (settings.IS_PRODUCTION, env_run_main))
        if (not settings.IS_PRODUCTION) and (env_run_main != 'true'):
            print('Exiting because detected running in reloader.')
            return

        print('Starting up for PID=%s, argv=%s...' % (os.getpid(), sys.argv))
        # Initialization of a singleton object from a C++ DLL
        # Raise an exception if this library was already initialized in this process

晚上,我重新启动了服务器,并按预期在日志中打印了以下内容:

[Sun Sep 15 22:50:34.928549 2019] [wsgi:error] [pid 11792:tid 1176] Starting up for PID=11792, argv=['mod_wsgi']...\r

但是,早上我注意到发生了一些奇怪的事情。看起来Apache启动了Web应用程序的新线程:

[Mon Sep 16 04:10:41.224464 2019] [wsgi:error] [pid 11792:tid 1160] Starting up for PID=11792, argv=['mod_wsgi']...\r

后来:

[Mon Sep 16 07:16:21.028429 2019] [mpm_winnt:error] [pid 11792:tid 2272] AH00326: Server ran out of threads to serve requests. Consider raising the ThreadsPerChild setting

我认为这不是两次调用AppConfig.ready()方法的问题,因为在两者之间有对网站的请求并且处理得很好。看起来,Django的AppConfig.ready()方法在Apache进程的每个工作线程中都被调用过一次。是这样吗在这种情况下,如何在每个进程中运行一次代码,而不是在由Apache和mod-wsgi支持的Django中每个线程运行一次代码?

1 个答案:

答案 0 :(得分:0)

根据您的apache配置,这可能是一个非答案。但是,大多数apache mod_wsgi配置建议您在重新启动wsgi进程之前实现某种max_request。您的代码可能是根据正常请求执行此操作,或者您的代码遇到了Django异常。

在这两种情况下,您都应该能够仅通过apache config或选项来分辨这一点。

https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIDaemonProcess.html

需要注意的一些有价值的选择

  

restart-interval = sss

     

以秒为单位定义时间限制   守护进程应在重新启动之前运行。

     

这可能用于定期强制重新启动WSGI应用程序   与Python对象参考相关的问题时的处理   计算周期,或不正确使用内存缓存,这会导致   持续的内存增长。

     

如果未定义此选项或将其定义为0,则守护程序   流程将是持久的,并将继续为请求提供服务,直到   Apache本身将重新启动或关闭。

     

避免将其设置得太低。这是因为不断重启   并且重新加载WSGI应用程序可能会导致不必要的加载   您的系统并影响性能。

     

您可以与此同时使用graceful-timeout选项   减少活动请求被请求的机会的选项   由于使用此选项而在重新启动时中断。

     

maximum-requests = nnn

     

定义请求数量的限制   守护进程应在关闭并重新启动之前进行处理。

     

这可能用于定期强制重新启动WSGI应用程序   与Python对象参考相关的问题时的处理   计算周期,或不正确使用内存缓存,这会导致   持续的内存增长。

     

如果未定义此选项或将其定义为0,则守护程序   流程将是持久的,并将继续为请求提供服务,直到   Apache本身将重新启动或关闭。

     

避免将其设置为可处理的网站上的少量请求   大量的流量。这是因为不断重启   重新加载WSGI应用程序可能会导致不必要的加载   系统并影响性能。仅当您没有时才使用此选项   由于内存使用问题,其他选择。尽快停止使用   内存问题已解决。

     

您可以与此同时使用graceful-timeout选项   减少活动请求被请求的机会的选项   由于使用此选项而在重新启动时中断。

     

inactivity-timeout = sss

     

定义允许的最大秒数   在守护进程关闭之前通过并在重新启动时通过   守护进程已进入空闲状态。为此目的   选项,处于空闲状态意味着没有当前活动的请求,也没有   收到新的请求。

     

存在此选项是为了允许不经常使用的应用程序在   守护进程重新启动,从而允许内存用于   回收,进程大小降回到初始启动   加载任何应用程序或处理请求之前的大小。

     

请注意,在重新启动WSGI应用程序过程之后,WSGI   应用程序将需要重新加载。这可能意味着   进程重新启动后,进程收到的请求可以是   慢点。如果您的WSGI应用程序在CPU上的启动成本很高   和时间,使用该选项可能不是一个好主意。

     

另请参见请求超时选项,用于在以下情况下强制重新启动进程   请求在指定的时间段内处于阻止状态。

     

请注意,与请求超时选项的功能类似,   是在请求被阻止时强制重新启动的一部分   由inactivity-timeout选项实现。请求超时为   在mod_wsgi的4.1.0版本中分解为一个单独的功能。

     

request-timeout = sss

     

定义a的最大秒数   允许该请求在守护进程重新启动之前运行。这个   可用于从请求被阻止的情况中恢复   无限期,如果所有请求线程都在此消耗掉   这样会导致整个WSGI应用程序流程被阻止。

     

此选项的行为方式会有所不同,具体取决于   守护进程仅使用一个线程,或将一个以上的线程用于   按照threads选项设置处理请求。

     

如果只有一个线程,那么该进程只能处理   一次超过一个请求,一旦超时,将重新启动   该过程将启动。

     

如果有多个线程,则将请求超时应用于   所有请求在所有线程上的平均运行时间。这个   意味着一个请求可以运行超过请求超时的时间。这是   这样做是为了减少中断其他正在运行的请求的可能性,   并导致用户看到故障。所以哪里还有容量   为了处理更多请求,如果出现以下情况,将重启进程   可能。

     

死锁超时= sss

     

定义允许的最大秒数   在守护进程关闭之前通过,并在一个守护进程之后重新启动   已检测到Python GIL上的潜在死锁。默认是   300秒。

     

存在此选项是为了解决守护程序进程冻结的问题   由于恶意的Python C扩展模块没有   在进入阻塞或长时间阻塞时正确释放Python GIL   运行操作。

     

startup-timeout = sss

     

定义允许的最大秒数   通过等待,看是否可以成功加载WSGI脚本文件   通过守护进程。超过超时时间后,该过程将   重新启动。

     

这可用于在瞬态时强制重新加载进程   第一次尝试加载WSGI脚本文件时发生问题,但是   随后的尝试仍然失败,因为   加载的状态保留,从而阻止尝试运行初始化   在同一过程中第二次。 Django套件可能会导致   这种情况由于Django本身的初始化不再可能   在同一过程中尝试了多次。