我的EC2实例大约每周一次,但有时甚至一天运行几次,几天后,我的EC2实例变得无响应。Munin的内存图讲述了一个非常简单的故事:分配给“应用程序”的内存开始增长,并且直到交换功能被完全使用并且实例被有效地压倒才停止。另一个自定义图形显示不断增长的过程是apache2。
我使用mod_php和一些PHP脚本运行标准的prefork Apache安装程序。正如您在下图中所看到的,发生了一些事情,这些事件触发apache2进程开始消耗越来越多的内存。我遇到了第一个绿色高峰,在事情失控之前重新启动了Apache。第二个峰值进一步扩大了,该实例必须完全重新启动。
我想知道的是如何最好地调试它。缺少使用FastCGI设置PHP并使其在自己的进程中运行的方法,找出它是Apache还是PHP和我的代码的组合导致过多内存使用的好方法是什么?你们将采取什么步骤来跟踪此问题?
更新:在涉及到strace之后,我能够跟踪泄漏,如Matt所建议的那样。
找到内存中逐渐且持续增长的apache2进程后,我在PHP脚本中添加了更多error_log()调用,以打印出在执行过程中各个点使用的RSS总量(使用ps的输出)。但是事实证明这是令人误解的-尽管似乎RSS仅在执行完脚本后才跳起来,但后来的调试表明事实并非如此。小心!
幸运的是,所有这些error_log()调用最终都非常有用。当我启动strace(strace -p <pid> -tt -o trace.log -s 256
)时,我发现对于每个请求,该进程都在分配约400k的内存(查找“ brk”系统调用,并从上次调用中减去第一个调用的参数-通常有几个传入)一个接一个)。然后,我搜索了包含我的error_log()消息的最新“写入”系统调用,该消息告诉我在脚本中的哪个位置分配了内存。通过再战略性地放置几个error_log()调用以更精确地定位位置,我终于找到了罪魁祸首。
当我们从PHP脚本中调用curl_exec()时,内存正在泄漏。一些与处理SSL连接有关的curl代码做错了-当我切换到HTTP时,泄漏消失了。Curl的changelog引用了7.19.5(我们在7.18.2中已修复)中的一些SSL内存泄漏,因此我将在下一个尝试。
同时,我正在以非常低的MaxRequestsPerChild运行,这使Apache处于合理范围之内。感谢大家!