4

我有一个 apache 网络服务器,我使用 mod_wsgi 使用烧瓶设置了一个网站。我有几个可能相关也可能不相关的问题。

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

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

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

问题 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 threads=4,那么当两个请求同时发出时,看似随机的问题就会一直出现。一个我设置processes=4 threads=1,那么看似随机的问题就不会发生了。尽管如此,内存的增加仍在发生,实际上现在将一直上升到系统的最大 RAM 并开始交换。

更新

虽然我还没有解决这个失控的 RAM 消耗问题,但我当前的应用程序几个月都没有遇到问题。显然它不是太流行,几天左右后,apache可能已经自动清除了RAM或其他东西。

现在,我做了另一个应用程序,它与前一个应用程序完全无关。之前的应用程序使用 matplotlib 生成大约 1 兆像素的图像。我的新应用程序正在使用 matplotlib 生成 20 兆像素图像和 1 兆像素图像。现在,当使用新应用程序生成 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(或我使用它的方式),而不是flask或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 以消除随机错误。

4

1 回答 1

0

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

或许还可以观看:

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


更新 1

根据您添加的配置,您缺少:

WSGIProcessGroup website

您的代码甚至不会在守护进程组中运行。因此,您将受制于您使用的任何 MPM 以及它正在运行的进程数。


更新 2

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

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

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


更新 3

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

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

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

于 2013-05-07T22:44:08.047 回答