apache上python flask应用程序的随机问题

时间:2013-05-07 20:37:15

标签: python apache memory matplotlib flask

我有一个apache webserver,我使用mod_wsgi使用flask设置了一个网站。我有几个可能相关或不相关的问题。

  1. 每次调用某个页面(运行一个执行繁重计算的函数需要2秒以上),内存会增加大约20兆字节。我的服务器开始时机器上的所有东西消耗了大约350兆字节。该服务器在htop中显示总共3,620兆字节。我多次重新加载这个页面后,服务器使用的总内存最终开始超过2,400兆字节,并停止增加。在达到这个级别之后,我无法让它消耗足够的内存以在数百页重新加载后进入交换。这是通过烧瓶或apache或python的设计?对我来说,如果有某种缓存机制,如果每次都调用相同的URL,就不会发生内存累积。如果我重新启动apache,则会释放内存。

  2. 有时调用此页面会导致调用函数错误输出,即使它们都是只读调用(不向磁盘写入任何数据),并且查询字符串对于每个页面都是相同的。

  3. 我有另一个页面(调用其他功能,计算量少得多),当与Web服务器上运行的其他页面同时调用时,随机出错或结果(图像)意外返回。

  4. 问题2和问题3可能与问题1有关吗?问题2和3可能是由于编程错误或机器内存不良造成的?我可以通过在大约40个firefox选项卡中加载相同的URL然后选择“重新加载所有选项卡”选项来重现随机性。

    应该提供哪些更多信息才能获得更好的答案?

    我尝试过放置

    import gc
    gc.collect()
    

    进入我的代码。

    我确实

        WSGIDaemonProcess website user=www-data group=www-data processes=2 threads=2 home=/web/website
        WSGIScriptAlias / /web/website/website.wsgi
        <Directory /web/website>
                WSGIProcessGroup website
                WSGIScriptReloading On
                WSGIApplicationGroup %{GLOBAL}
                Order deny,allow
                Allow from all
        </Directory>
    

    在我的/ etc / apache2 / sites-available / default文件中。如果只创建了总共4个线程,那么内存似乎不应该增长那么多吗?

    更新

    如果我设置processes = 1个线程= 4,则一次发出两个请求时会出现看似随机的问题。一个我设置进程= 4个线程= 1,然后看似随机的问题不会发生。内存的增加仍在发生,实际上现在将一直上升到系统的最大RAM并开始交换。

    更新

    虽然我没有解决这个失控的RAM消耗问题,但是我的当前应用程序几个月没有出现问题。显然它并不太受欢迎,经过几天左右的时间,apache可能已经自动清除RAM或其他东西。

    现在,我已经制作了另一个应用程序,它与前一个应用程序完全无关。之前的应用程序使用matplotlib生成大约100万像素的图像。我的新应用程序使用matplotlib生成2000万像素图像和100万像素图像。现在,当使用新应用程序生成20万像素图像时,问题变得越来越大。在整个交换空间被填满之后,某些东西似乎被杀死了,并且在有一些RAM和交换空间可用的情况下,事情以适当的速度工作了一段时间,但是当RAM被消耗时运行速度要慢得多。以下是正在运行的进程。我认为没有任何额外的僵尸进程在运行。

    $ ps -ef|grep apache  
    root      3753     1  0 03:45 ?        00:00:02 /usr/sbin/apache2 -k start  
    www-data  3756  3753  0 03:45 ?        00:00:00 /usr/sbin/apache2 -k start  
    www-data  3759  3753  0 03:45 ?        00:02:06 /usr/sbin/apache2 -k start  
    www-data  3762  3753  0 03:45 ?        00:00:01 /usr/sbin/apache2 -k start  
    www-data  3763  3753  0 03:45 ?        00:00:01 /usr/sbin/apache2 -k start  
    test      4644  4591  0 12:27 pts/1    00:00:00 tail -f /var/log/apache2/access.log  
    www-data  4894  3753  0 21:34 ?        00:00:37 /usr/sbin/apache2 -k start  
    www-data  4917  3753  2 22:33 ?        00:00:36 /usr/sbin/apache2 -k start  
    www-data  4980  3753  1 22:46 ?        00:00:12 /usr/sbin/apache2 -k start  
    

    当我看到htop时,我有点困惑,因为它显示了比top或ps更多的进程。

    更新

    我已经发现内存泄漏是由于matplotlib(或者我使用它的方式),而不是烧瓶或apache,所以我最初发布的问题2和3确实是问题1的另一个问题。这是我在ipython中以交互方式消除/重现问题的基本功能。

    def BigComputation():
        import cStringIO
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt
    
        #larger figure size causes more RAM to be used when savefig is run.
        #this function also uses some RAM that is never released automatically
        #if plt.close('all') is never run, but it is a small amount,
        #so it is hard to tell unless run BigComputation thousands of times.
        TheFigure=plt.figure(figsize=(250,8))
    
        file_output = cStringIO.StringIO()
    
        #causes lots of RAM to be used, and never released automatically
        TheFigure.savefig(file_output)
    
        #releases all the RAM that is never released automatically
        plt.close('all')
    
        return None
    

    摆脱RAM泄漏的技巧是运行

    plt.close('all')
    

    在BigComputation()中,否则,BigComputation()将在每次调用函数时保持累积RAM。我不知道我是不是只是不恰当地使用matplotlib或者编码技术不好,但我真的认为一旦BigComputation()返回,它应该释放除了任何全局对象或它返回的对象之外的所有内存。在我看来,matplotlib必须以不恰当的方式创建一些全局变量,因为我不知道它们的名称是什么。

    我想我的问题现在在哪里,为什么我需要plt.close('all')?我还需要尝试Graham Dumpleton的建议,以便进一步诊断我的apache配置,看看为什么我需要在apache中设置threads = 1以使随机错误消失。

1 个答案:

答案 0 :(得分:0)

显然是一个编程问题,但通过运行多进程配置会变得更糟。读:

也许也可以观看:

他们解释了需要注意如何设置Apache。


更新1

根据您添加的配置,您将丢失:

WSGIProcessGroup website

您的代码甚至不会在守护程序进程组中运行。因此,无论您使用何种MPM以及它正在运行多少个进程,您都会受到怜悯。


更新2

您的目录块错误。它不是指目录。应该是:

<Directory /web>
        WSGIProcessGroup website
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
</Directory>

不需要WSGIScriptReloading指令,因为这是默认设置。


更新3

由于您没有提供确切的配置,因此我们现在无法确定您所提供的内容是相同的,为了绝对确认您正在使用守护程序模式,因此只有最多2个进程,请执行以下测试:

你想得到'网站'和''。意思是守护进程模式和主要解释器。

我们知道我们实际上只谈论两个守护进程的内存使用情况。