一、问题描述
过了个周末发现博客网站变得很慢,发布文章特别迟钝。经过登录服务器查看资源使用情况发现是 php-fpm 进程将内存全部占用,才导致了变慢的情况。通过查找了解了其中的部分原理:
LNMP 架构中 PHP 是运行在 FastCGI 模式下,按照官方的说法,php-cgi 会在每个请求结束的时候会回收脚本使用的全部内存,但是并不会释放给操作系统,而是继续持有以应对下一次 PHP 请求。而 php-fpm 是 FastCGI 进程管理器,用于控制 php 的内存和进程等。
所以,解决的办法就是通过 php-fpm 优化总的进程数和单个进程占用的内存,从而解决 php-fpm 进程占用内存大和不释放内存的问题。
二、分析思路
查看服务器内存
[root@dameng linuxscript]# free -m total used free shared buff/cache available Mem: 3736 3469 114 1 151 72 Swap: 4095 2131 1964
占用 CPU 最多的 10 个进程
[root@dameng linuxscript]# ps aux|head -1;ps aux|sort -rn -k +3|head USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND www 87009 0.0 1.9 424552 73072 ? S Dec13 1:30 php-fpm: pool www www 77548 0.0 0.1 97456 4200 ? S Dec12 0:11 nginx: worker process www 77547 0.0 0.1 97460 5780 ? S Dec12 0:11 nginx: worker process www 7384 0.0 2.4 436428 91832 ? S Dec09 6:26 php-fpm: pool www www 73344 0.0 2.4 428988 93996 ? S Dec12 3:25 php-fpm: pool www www 6787 0.0 2.4 441144 92476 ? S Dec09 6:29 php-fpm: pool www www 6785 0.0 2.4 446040 92264 ? S Dec09 6:30 php-fpm: pool www www 6738 0.0 1.9 441812 76064 ? S Dec09 6:43 php-fpm: pool www www 6737 0.0 2.3 434280 90192 ? S Dec09 6:29 php-fpm: pool www www 6736 0.0 2.4 460112 93820 ? S Dec09 6:29 php-fpm: pool www
占用内存最多的 10 个进程
[root@dameng linuxscript]# ps aux|head -1;ps aux|sort -rn -k +4|head USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND www 1183 0.0 2.6 445260 100948 ? S Dec09 7:05 php-fpm: pool www www 1177 0.0 2.6 457820 99796 ? S Dec09 6:54 php-fpm: pool www www 1176 0.0 2.6 456788 100032 ? S Dec09 6:31 php-fpm: pool www www 1179 0.0 2.5 438904 98660 ? S Dec09 6:32 php-fpm: pool www www 7384 0.0 2.4 436428 91832 ? S Dec09 6:26 php-fpm: pool www www 73344 0.0 2.4 428988 93996 ? S Dec12 3:25 php-fpm: pool www www 6787 0.0 2.4 441144 92476 ? S Dec09 6:29 php-fpm: pool www www 6785 0.0 2.4 446040 92264 ? S Dec09 6:30 php-fpm: pool www www 6736 0.0 2.4 460112 93820 ? S Dec09 6:29 php-fpm: pool www www 1191 0.0 2.4 440416 94024 ? S Dec09 7:10 php-fpm: pool www
可以看到除去 nginx 的两个进程,其余全部是 php-fpm。
查看当前 php-fpm 总进程数
[root@dameng ~]# ps -ylC php-fpm --sort:rss S UID PID PPID C PRI NI RSS SZ WCHAN TTY TIME CMD S 0 900 1 0 80 0 4268 59433 - ? 00:00:10 php-fpm S 1005 1174 900 0 80 0 10196 97401 - ? 00:07:09 php-fpm S 1005 1185 900 0 80 0 11732 100252 - ? 00:06:29 php-fpm S 1005 107461 900 0 80 0 31796 97600 - ? 00:00:19 php-fpm S 1005 107459 900 0 80 0 66224 104786 - ? 00:00:20 php-fpm S 1005 107452 900 0 80 0 73024 104239 - ? 00:00:20 php-fpm S 1005 107451 900 0 80 0 76952 108688 - ? 00:00:19 php-fpm S 1005 6463 900 0 80 0 79508 108117 - ? 00:06:31 php-fpm S 1005 6576 900 0 80 0 82336 113815 - ? 00:06:32 php-fpm S 1005 73344 900 0 80 0 82372 107247 - ? 00:03:25 php-fpm S 1005 1193 900 0 80 0 82636 109523 - ? 00:06:28 php-fpm S 1005 1184 900 0 80 0 84272 109207 - ? 00:06:32 php-fpm S 1005 1180 900 0 80 0 84936 109765 - ? 00:06:50 php-fpm S 1005 1189 900 0 80 0 85408 113732 - ? 00:06:32 php-fpm S 1005 6737 900 0 80 0 85636 108570 - ? 00:06:29 php-fpm S 1005 1191 900 0 80 0 86452 110104 - ? 00:07:10 php-fpm S 1005 107467 900 0 80 0 86716 105308 - ? 00:00:19 php-fpm S 1005 107436 900 0 80 0 86920 106680 - ? 00:00:20 php-fpm S 1005 1178 900 0 80 0 88236 108623 - ? 00:06:29 php-fpm S 1005 1187 900 0 80 0 88968 108701 - ? 00:06:33 php-fpm S 1005 1188 900 0 80 0 89208 109055 - ? 00:06:30 php-fpm S 1005 87009 900 0 80 0 89692 105626 - ? 00:01:31 php-fpm S 1005 1181 900 0 80 0 91280 108432 - ? 00:06:31 php-fpm S 1005 107466 900 0 80 0 91612 106331 - ? 00:00:20 php-fpm S 1005 7384 900 0 80 0 91716 109107 - ? 00:06:26 php-fpm S 1005 6787 900 0 80 0 92396 110286 - ? 00:06:29 php-fpm S 1005 107462 900 0 80 0 93112 105760 - ? 00:00:19 php-fpm S 1005 1182 900 0 80 0 93404 108442 - ? 00:06:32 php-fpm S 1005 6736 900 0 80 0 93448 115028 - ? 00:06:29 php-fpm S 1005 6785 900 0 80 0 93800 111510 - ? 00:06:30 php-fpm S 1005 107460 900 0 80 0 94540 107895 - ? 00:00:20 php-fpm S 1005 1190 900 0 80 0 94812 108684 - ? 00:06:29 php-fpm S 1005 1177 900 0 80 0 95120 114455 - ? 00:06:54 php-fpm S 1005 1186 900 0 80 0 95132 119251 - ? 00:06:34 php-fpm S 1005 107468 900 0 80 0 95508 107337 - ? 00:00:20 php-fpm S 1005 6738 900 0 80 0 96216 109941 - ? 00:06:44 php-fpm S 1005 1192 900 0 80 0 96412 108828 - ? 00:06:28 php-fpm S 1005 1175 900 0 80 0 96776 110023 - ? 00:07:17 php-fpm S 1005 1179 900 0 80 0 97792 109726 - ? 00:06:32 php-fpm S 1005 1183 900 0 80 0 98208 111315 - ? 00:07:05 php-fpm S 1005 1176 900 0 80 0 98856 114197 - ? 00:06:31 php-fpm [root@dameng ~]# ps -ylC php-fpm --sort:rss|wc -l 42 [root@dameng ~]# ps -fe |grep "php-fpm"|grep "pool"|wc -l 40
查看当前 php-fpm 进程的内存占用情况及启动时间
[root@dameng ~]# ps -e -o 'pid,comm,args,pcpu,rsz,vsz,stime,user,uid'|grep www|sort -nrk5 87009 php-fpm php-fpm: pool www 0.0 89692 422504 Dec13 www 1005 77548 nginx nginx: worker process 0.0 3932 97456 Dec12 www 1005 77547 nginx nginx: worker process 0.0 5472 97460 Dec12 www 1005 7384 php-fpm php-fpm: pool www 0.0 91716 436428 Dec09 www 1005 73344 php-fpm php-fpm: pool www 0.0 82372 428988 Dec12 www 1005 6787 php-fpm php-fpm: pool www 0.0 92396 441144 Dec09 www 1005 6785 php-fpm php-fpm: pool www 0.0 93800 446040 Dec09 www 1005 6738 php-fpm php-fpm: pool www 0.0 96216 439764 Dec09 www 1005 6737 php-fpm php-fpm: pool www 0.0 85636 434280 Dec09 www 1005 6736 php-fpm php-fpm: pool www 0.0 93448 460112 Dec09 www 1005 6576 php-fpm php-fpm: pool www 0.0 82336 455260 Dec09 www 1005 6463 php-fpm php-fpm: pool www 0.0 79508 432468 Dec09 www 1005 1193 php-fpm php-fpm: pool www 0.0 82636 438092 Dec09 www 1005 1192 php-fpm php-fpm: pool www 0.0 96412 435312 Dec09 www 1005 1191 php-fpm php-fpm: pool www 0.0 86452 440416 Dec09 www 1005 1190 php-fpm php-fpm: pool www 0.0 94812 434736 Dec09 www 1005 1189 php-fpm php-fpm: pool www 0.0 85408 454928 Dec09 www 1005 1188 php-fpm php-fpm: pool www 0.0 89208 436220 Dec09 www 1005 1187 php-fpm php-fpm: pool www 0.0 88968 434804 Dec09 www 1005 1186 php-fpm php-fpm: pool www 0.0 95132 477004 Dec09 www 1005 1185 php-fpm php-fpm: pool www 0.0 11732 401008 Dec09 www 1005 1184 php-fpm php-fpm: pool www 0.0 84272 436828 Dec09 www 1005 1183 php-fpm php-fpm: pool www 0.0 98208 445260 Dec09 www 1005 1182 php-fpm php-fpm: pool www 0.0 93404 433768 Dec09 www 1005 1181 php-fpm php-fpm: pool www 0.0 91280 433728 Dec09 www 1005 1180 php-fpm php-fpm: pool www 0.0 84936 439060 Dec09 www 1005 1179 php-fpm php-fpm: pool www 0.0 97792 438904 Dec09 www 1005 1178 php-fpm php-fpm: pool www 0.0 88236 434492 Dec09 www 1005 1177 php-fpm php-fpm: pool www 0.0 95120 457820 Dec09 www 1005 1176 php-fpm php-fpm: pool www 0.0 98856 456788 Dec09 www 1005 1175 php-fpm php-fpm: pool www 0.0 96776 440092 Dec09 www 1005 1174 php-fpm php-fpm: pool www 0.0 10196 389604 Dec09 www 1005 110196 grep grep --color=auto www 0.0 1108 12140 10:57 root 0 107468 php-fpm php-fpm: pool www 0.0 95508 429348 Dec15 www 1005 107467 php-fpm php-fpm: pool www 0.0 86716 421232 Dec15 www 1005 107466 php-fpm php-fpm: pool www 0.0 91612 425324 Dec15 www 1005 107462 php-fpm php-fpm: pool www 0.0 93112 423040 Dec15 www 1005 107461 php-fpm php-fpm: pool www 0.0 31796 390400 Dec15 www 1005 107460 php-fpm php-fpm: pool www 0.0 94540 431580 Dec15 www 1005 107459 php-fpm php-fpm: pool www 0.0 66224 419144 Dec15 www 1005 107452 php-fpm php-fpm: pool www 0.0 73024 416956 Dec15 www 1005 107451 php-fpm php-fpm: pool www 0.0 76952 434752 Dec15 www 1005 107436 php-fpm php-fpm: pool www 0.0 86920 426720 Dec15 www 1005
查看当前 php-fpm 进程平均占用内存情况
[root@dameng ~]# ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"M") }' 79M
所以,罪魁祸首就是 php-fpm。
三、解决方法
php-fpm.conf 就是 php-fpm 的配置文件,一般路径为:/usr/local/php/etc/php-fpm.conf
修改如下参数
pm = dynamic pm.start_servers = 20 pm.min_spare_servers = 10 pm.max_spare_servers = 30 pm.max_requests = 100
- pm = dynamic #指定进程管理方式,有 3 种可供选择:static、dynamic 和 ondemand。
- pm.max_children = 30 #static 模式下创建的子进程数或 dynamic 模式下同一时刻允许最大的 php-fpm 子进程数量。
- pm.start_servers = 20 #动态方式下的起始 php-fpm 进程数量。
- pm.min_spare_servers = 10 #动态方式下服务器空闲时最小 php-fpm 进程数量。
- pm.max_spare_servers = 30 #动态方式下服务器空闲时最大 php-fpm 进程数量。
- pm.max_requests = 300 #php-fpm 子进程能处理的最大请求数。
其中 pm.max_requests 是设置每个子进程重生之前服务的请求数,对于可能存在内存泄漏的第三方模块来说是非常有用的。
注意
pm.max_requests 设置得太小也容易出现无进程可用(502 状态),一般来说,普通网站设置 max_requests 300~500 合适,但也要结合 pm.start_servers 和你的网站访问量来看,也可以适当调大和减少,这个是因情况而异的。
修改完配置文件后,保存退出,检测配置文件语法是否正确
[root@dameng ~]# /usr/local/php/sbin/php-fpm -t [16-Dec-2024 13:07:50] NOTICE: configuration file /usr/local/php/etc/php-fpm.conf test is successful
重启 php-fpm
[root@dameng etc]# service php-fpm restart Gracefully shutting down php-fpm . done Starting php-fpm done
再次查看服务器内存使用情况
[root@dameng etc]# free -m total used free shared buff/cache available Mem: 3736 289 3160 2 285 3224 Swap: 4095 895 3200
可以看到服务器内存使用率已经降下来了,后续再做观察。
经过一周的观察,服务器内存可以稳定下来,available 始终保持在 1000 左右,表现还算良好。但是,在我使用 WordPress 插件 Duplicator 进行备份后发现,available 又减少了一百多,看着不是很舒服。所以决定在服务器添加定时任务,每天凌晨 1 点重启 php-fpm 服务以释放内存。
crontab -e ## 新增内容 0 1 * * * service php-fpm restart ## 保存退出
这样服务器内存可以始终保持在一个健康的水平。