我如何确定在我的基于Apache / PHP的Web应用程序中明显的内存泄漏的原因?

大约每周一次,但有时甚至几天后运行良好,我的EC2实例变得没有反应。 Munin的内存图表讲述了一个非常简单的故事:分配给“应用程序”的内存开始增长,直到swap完全被使用并且实例被有效地closures为止。 另一个自定义图表显示,不断增长的过程是apache2。

我使用mod_php和几个PHP脚本运行标准的prefork Apache安装程序。 正如你在下面的图表中看到的,触发apache2进程开始消耗越来越多的内存的事情发生了。 我发现了第一个绿色尖峰,并在事情失控之前重新启动了Apache。 第二个秒杀得到了更远,实例必须彻底重新启动。

Munin记忆图

我想知道的是如何最好的debugging。 使用FastCGI设置PHP并让它在自己的进程中运行的缺点是什么是一个很好的方法来找出它是Apache还是PHP和我的代码的组合导致过度的内存使用? 你们会采取什么措施来追踪这个问题?


更新:我能跟踪泄漏后,涉及strace,如马特build议如下。

在find一个在内存中不断增长的apache2进程之后,我又添加了一些error_log()调用到我的PHP脚本中,这个脚本打印出了执行中各个点(使用ps的输出)使用的RSS总量。 然而事实certificate这是误导性的 – 虽然看起来RSS只是在我的脚本执行完毕后才跳转,后来的debugging显示事实并非如此。 小心!

幸运的是,所有这些error_log()调用最终都是有用的。 当我启动strace( strace -p <pid> -tt -o trace.log -s 256 )时,我看到对于每个请求,进程分配了大约400k的内存(寻找“brk”系统调用并减去来自最后一次呼叫的第一个呼叫的参数 – 一些通常会一个接一个地进入)。 然后,我search了包含我的error_log()消息的最近的“写入”系统调用,该消息告诉我脚本内存分配的哪一点。 有一些更具战略意义的调用error_log()调用来更准确地查明位置,我终于find了罪魁祸首。

当我们从我们的PHP脚本调用curl_exec()时,内存泄漏。 一些与处理SSL连接有关的curl代码是做错了事 – 当我切换到HTTP时泄漏消失了。 Curl的更新日志引用了一些在7.19.5(我们在7.18.2)中修复的SSL内存泄漏,所以我会在下一步尝试。

与此同时,我正在运行一个非常低的MaxRequestsPerChild,使Apache保持在合理的范围内。 感谢大家!

追查什么是导致问题可能是一个痛苦的屁股。 如果我有这样的问题,我会做的第一件事是减lessMaxRequestsPerChild到一个非常低的数字(〜100-200),看看是否有所作为。 如果是这样,那么你可能有代码在循环中泄漏内存,你会想要运行代码审计。

另一件要看的事情是Apache的fullstatus,看你是否可以找出什么特定的请求导致内存泄漏。 获取可疑进程的PID并在其上运行一个strace。

星期五@正好11点? 这是否对应于备份时间? 您的系统当时是否有可用于处理和备份的I / O? 你是否趋势软件也趋势#特效或甚至阿帕奇记分板,如何磁盘I / O?

我要做的第一件事就是计算每个proc需要多less内存,然后为apache中的MaxRequests设置一个合理的限制,以便$ procmem * $ procs不能超过可用的内存。 我怀疑你的实例需要重新启动,因为OOM开始了可能(通常)不是很有成果的巫术追捕。 你需要确保你的盒子可以处理这些沉重的时间,保持在其范围内,而不是去交换,当然不是OOM。 如果你有cronjobs,这很难,如果cronjobs单方面运行而没有确保运行是安全的(即每5分钟脚本没有检查最后5分钟是否仍在运行),这是非常困难的。

现在你已经确保即使事情出错了,你不需要重新启动你的盒子,事情会开始好转。 您可以在这些繁重的时间login,并了解使用top,dstat,free -m,iostat等进行的操作。

马特的方法可能值得尝试,但只能作为一个排除故障的工具,我不build议保持这种方式,因为它会使整个问题难以find下一次你要找它。 这就是说,它只会真正解决问题与Apache /模块,而不是在你的代码中的任何东西。 我认为你会同意机会是好的,这不是在Apache模块中的某种内存泄漏(假设你使用的是一个有信誉的发行版)。

要问的第一个问题是通过Apache运行的应用程序是什么?

这是你写的,还是第三方的应用程序?

它引用了什么其他组件/包?

你是最新的包?

你的httpd.conf文件中的任何特定的性能相关?

如果您的问题是由PHP应用程序引起的,并且您自己编写了软件,那么我build议您使用例如PHP Quick Profiler等分析器 。 如果您有很多数据库事务正在进行,那么像Kontrollbase这样的软件可以帮助您find问题。