从今天早上开始,我们的一个网络服务器的内存被 php 填满,最终导致服务器开始交换、速度变慢并变得不可用(ssh 登录需要 5 分钟,然后有时会完全死机)...
我想知道您将如何解决此类问题。
Jul 23 06:16:31 websrv2 kernel: [10409040.981882] php-cgi invoked oom-killer: gfp_mask=0x200da, order=0, oom_adj=0
Jul 23 06:16:31 websrv2 kernel: [10409040.981888] php-cgi cpuset=/ mems_allowed=0
Jul 23 06:16:31 websrv2 kernel: [10409040.981892] Pid: 27697, comm: php-cgi Not tainted 2.6.32-5-amd64 #1
Jul 23 06:16:31 websrv2 kernel: [10409040.981894] Call Trace:
Jul 23 06:16:31 websrv2 kernel: [10409040.981903] [<ffffffff810b6714>] ? oom_kill_process+0x7f/0x23f
Jul 23 06:16:31 websrv2 kernel: [10409040.981908] [<ffffffff8106bdee>] ? timekeeping_get_ns+0xe/0x2e
Jul 23 06:16:31 websrv2 kernel: [10409040.981912] [<ffffffff810b6c38>] ? __out_of_memory+0x12a/0x141
Jul 23 06:16:31 websrv2 kernel: [10409040.981916] [<ffffffff810b6d8f>] ? out_of_memory+0x140/0x172
Jul 23 06:16:31 websrv2 kernel: [10409040.981921] [<ffffffff810baaf4>] ? __alloc_pages_nodemask+0x4ec/0x5fc
Jul 23 06:16:31 websrv2 kernel: [10409040.981927] [<ffffffff810d92d8>] ? read_swap_cache_async+0x5d/0xf3
Jul 23 06:16:31 websrv2 kernel: [10409040.981931] [<ffffffff810d93c5>] ? swapin_readahead+0x57/0x98
Jul 23 06:16:31 websrv2 kernel: [10409040.981937] [<ffffffff8100c18d>] ? __raw_callee_save_xen_pte_val+0x11/0x1e
Jul 23 06:16:31 websrv2 kernel: [10409040.981941] [<ffffffff810cd245>] ? handle_mm_fault+0x47f/0x80f
Jul 23 06:16:31 websrv2 kernel: [10409040.981947] [<ffffffff813001a6>] ? do_page_fault+0x2e0/0x2fc
Jul 23 06:16:31 websrv2 kernel: [10409040.981952] [<ffffffff812fe045>] ? page_fault+0x25/0x30
Jul 23 06:16:31 websrv2 kernel: [10409040.981954] Mem-Info:
我尝试按照内存使用情况对进程进行排序:
ps -e -orss=,args=|sort -b -k1,1n|pr -TW$COLUMNS
我看到很多 /usr/bin/php-cgi 消耗内存。如何限制 PHP 的总体内存消耗,以便服务器不会达到极限而耗尽所有内存/交换空间并变得不可用?
更多系统信息:
ii php5 5.3.3-7+squeeze18 server-side, HTML-embedded scripting language (metapackage)
ii apache2 2.2.16-6+squeeze11 Apache HTTP Server metapackage
答案1
您可以使用 cgroups 限制用户(运行 php-cgi 进程的用户)的内存使用量。
例如,要限制用户的内存使用量,您可以执行以下操作:
# file: /etc/cgconfig.conf
group php {
memory {
memory.limit_in_bytes = "2G";
}
}
然后你必须将你的 php-cgi 用户添加到这个 cgroup-group:
# file: /etc/cgrules.conf
phpcgiuser memory php
如果您想限制每个进程的内存使用量,可以使用 ulimit(每个进程 100 MB)来实现。
# file: /etc/security/limits.conf
phpcgiuser hard as 102400
编辑:尽管如此,您还是应该分析导致内存泄漏的软件。
答案2
如果这是经常使用的结果,您应该检查这些 PHP 脚本是否存在内存泄漏、无限循环和此类可怕的问题。
答案3
你用的是什么操作系统?我在所有网络服务器上为所有网络应用程序提供服务时,所做的是:
- 我为每个单独的 Web 应用程序创建单独的池。
- 我在 php.ini 中限制了它们可以吸收的内存量(memory_limit = 2048M)
- 我已经修改了所有池,以便运行 Web 服务器的 NginX 用户实际上也运行 PHP 池。
通过这种方式,我从来没有遇到过你现在遇到的情况,因为每次我有一个应用程序试图用它自己溢出 RAM 时,它都会被踢出,而不会对其余的 Web 应用程序产生任何影响。
然而,我也强烈建议找到这次大规模溢出的罪魁祸首,它可能是一次攻击,也可能是一段编写错误的代码(我认为是第二种)。
但我最推荐的是升级你的 PHP 版本!!!! PHP 5.5 已经过时了,不再提供任何支持。如果无法升级到 7.1,那么至少升级到 5.6。