![PHP FPM 循环导致巨大的 RAM 消耗](https://linux22.com/image/779430/PHP%20FPM%20%E5%BE%AA%E7%8E%AF%E5%AF%BC%E8%87%B4%E5%B7%A8%E5%A4%A7%E7%9A%84%20RAM%20%E6%B6%88%E8%80%97.png)
几个 ubuntu 服务器,使用 php8.0 / php8.1,以 NGINX 作为网络服务器,导致了这个问题,我的内存正在填满 - 基于传入流量(req/s),所以我必须每 30 分钟重新启动一次 fpm 进程,因为否则 FPM 会变得非常慢并且传入的请求开始排队。
由于我有几台服务器,我尝试在所有服务器上对 PM 进行不同的设置,以检查问题是否不会发生。因此,我尝试使用静态/动态/按需 > 的 PM,大约一小时后,它们都非常慢。我还尝试对它们使用 max_request,让它们自动循环,而不是让它们永远存在 - 没有任何成功。
没有段错误,我正在使用 apcu 和 opcache 作为扩展,尝试关闭 apcu,但无论如何 RAM 都在堆积 - 直到 FPM 变慢。我发现每次 fpm 重新启动都会导致大量小页面错误(300k),并且在通常的运行时最多为 40-80k >,当达到 100k 时,它开始变慢。
此外,即使没有 apcu,共享内存也会堆积,因此我认为每个常规循环(不是 fpm 重启)都会导致共享内存出现问题。我也没有看到任何关于尝试分配过多 RAM 或以任何方式超出 RAM 的错误。
很高兴我能核实任何想法。
编辑:如果我可以提供任何进一步的信息,请随时告诉我
编辑2:安装了ps_mem,发现只有共享内存随着时间的推移而增加,而不是子进程本身声明/定义的内存。
编辑 3:当前设置之一基本上是这样的:
listen = /run/php/php8.1-main-fpm.sock
;listen.backlog = 8000
listen.backlog = -1
listen.owner = www
listen.group = www-data
listen.mode = 0660
user = www
group = www
slowlog = /var/log/slow-php8.1-fpm.log
request_slowlog_timeout = 2s
pm = static
pm.max_children = 700
pm.max_requests = 0
request_terminate_timeout = 7s
pm.status_path = /status
我也尝试通过 ps_mem 来解决这个问题。重启后,输出如下:
$ ps_mem | grep php
2.2 GiB + 112.2 MiB = 2.3 GiB php-fpm8.1 (903)
两分钟后:
$ ps_mem | grep php
2.3 GiB + 164.4 MiB = 2.4 GiB php-fpm8.1 (903)
十五分钟后:
$ ps_mem | grep php
2.5 GiB + 272.6 MiB = 2.8 GiB php-fpm8.1 (903)
该服务器有 64 个 CPU 和大约 128 GB 的 Ram。
编辑 3:刚刚有一个很好的发现,这影响了当前的问题 - 每分钟执行此命令有助于解决问题
sync; echo 1 > /proc/sys/vm/drop_caches
这是一个临时的解决方案——想发现问题的根源。
答案1
根据您的特定应用程序,单个页面请求可能需要一个 PHP-FPM 工作器,且最低 RAM 仅大约为 80MB。
将其乘以你的配置pm.max_children = 700
,你会发现,随着许多请求进入并使所有工作人员忙碌,你会得到至少使用了 56GB。这是当您的应用非常精简时的情况。每个请求很容易占用 100MB 或 120MB,等等。
这只pm.max_requests = 0
会让情况变得更糟。PHP 工作进程中总是存在内存泄漏和错误。你必须将其设置为某个值,以便回收工作者。否则,工作者将在 RAM 中无限增长,直到您重新启动 PHP-FPM 并清除流量。将其设置为1000
或10000
(在请求数达到该值后,工作者将被回收),但绝不能设置为0
。
最后,不要这样做request_slowlog_timeout = 2s
。慢速日志记录不适合生产环境。(不过暂时没问题)。