Web 中间件 php-fpm 配置调优

Web 中间件 php-fpm 配置调优

一、php-fpm.conf 主要配置参数

  • pm = dynamic; 表示使用哪种进程数量管理方式

    dynamic 表示 php-fpm 进程数是动态的,最开始是 pm.start_servers 指定的数量,如果请求较多,则会自动增加,保证空闲的进程数不小于pm.min_spare_servers,如   果进程数较多,也会进行相应清理,保证多余的进程数不多于 pm.max_spare_servers;
    
    static 表示 php-fpm 进程数是静态的,进程数自始至终都是 pm.max_children 指定的数量,不再增加或减少。
  • pm.max_children = 300; 静态方式下开启的php-fpm进程数量
  • pm.start_servers = 20; 动态方式下的起始php-fpm进程数量
  • pm.min_spare_servers = 5; 动态方式下的最小php-fpm进程数量
  • pm.max_spare_servers = 35; 动态方式下的最大php-fpm进程数量

    注意:数值设置,参考自己的实际硬件配置,可以参考 总内存/30M 来计算。

如果 pm 设置为 static,那么其实只有 pm.max_children 这个参数生效。系统会开启设置数量的 php-fpm 进程。

如果 pm设置为 dynamic,那么 pm.max_children 参数失效,后面3个参数生效。系统会在 php-fpm 运行开始的时候启动 pm.start_servers 个 php-fpm 进程,然后根据系统的需求动态在 pm.min_spare_servers 和 pm.max_spare_servers 之间调整 php-fpm 进程数。

1、pm 方式选择

事实上,跟 Apache 一样,运行的 PHP 程序在执行完成后,或多或少会有内存泄露的问题。这也是为什么开始的时候一个 php-fpm 进程只占用 3M 左右内存,运行一段时间后就会上升到 20-30M 的原因了。

对于内存大的服务器(比如8G以上)来说,用静态的 max_children 实际上更为妥当,因为这样不需要进行额外的进程数目控制,会提高效率。因为频繁开关 php-fpm 进程也会有时滞,所以内存够大的情况下开静态效果会更好。数量也可以根据 总内存/30M 得到,比如 8GB 内存可以设置为100,那么 php-fpm 耗费的内存就能控制在 2G-3G 的样子。

如果内存稍微小点,比如 1~2G,那么指定动态的进程数量更加有利于服务器的稳定。这样可以保证 php-fpm 只获取够用的内存,将不多的内存分配给其他应用去使用,会使系统的运行更加畅通。

对于小内存的服务器来说,比如 256M 内存的 VPS,即使按照一个 20M 的内存量来算,10个 php-cgi 进程就将耗掉200M内存,那系统的崩溃就应该很正常了。

因此应该尽量地控制 php-fpm 进程的数量,大体明确其他应用占用的内存后,给它指定一个静态的小数量,会让系统更加平稳一些。

或者使用动态方式,因为动态方式会结束掉多余的进程,可以回收释放一些内存,所以推荐在内存较少的服务器或VPS上使用,具体最大数量根据 总内存/20M 得到。

比如说 512M 的 VPS,建议 pm.max_spare_servers 设置为 20。至于 pm.min_spare_servers,则建议根据服务器的负载情况来设置,比较合适的值在 5~10 之间。

总结:内存小的建议用动态(pm = dynamic),内存大的建议用静态(pm = static)。

2、pm.max_children 设置多大

这个值原则上是越大越好,php-cgi的进程多了就会处理的很快,排队的请求就会很少。

设置”max_children” 也需要根据服务器的性能进行设定。

计算方式如下:

一般来说一台服务器正常情况下每一个php-cgi所耗费的内存在20M~30M左右,因此我的”max_children”我设置成40个,20M*40=800M也就是说在峰值的时候所有PHP-CGI所耗内存在800M以内,低于我的有效内存2Gb。

而如果我 的”max_children”设置的较小,比如5-10个,那么php-cgi就会“很累“,处理速度也很慢,等待的时间也较长,占用的CPU也很高。

如果长时间没有得到处理的请求就会出现 504 Gateway Time-out 这个错误,而正在处理的很累的那几个php-cgi如果遇到了问题就会出现 502 Bad gateway 这个错误。

max_children较好的设置方式根据req/s(吞吐率,单位时间里服务器处理的最大请求数,单位req/s)来设置,若程序是 100 req/s 的处理能力,那么就设置 100比较好,这是动态来调整的。

3、request_terminate_timeout 设置多大

计算方式如下:

如果你的服务器性能足够好,且宽带资源足够充足,PHP脚本没有循环或BUG的话你可以直接将”request_terminate_timeout”设 置成0s。0s的含义是让PHP-CGI一直执行下去而没有时间限制。

而如果你做不到这一点,也就是说你的PHP-CGI可能出现某个BUG,或者你的宽带不够充足或者其他的原因导致你的PHP-CGI能够假死那么就建议你给”request_terminate_timeout”赋一个值,这个值可以根 据你服务器的性能进行设定。

一般来说性能越好你可以设置越高,20分钟-30分钟都可以。由于我的服务器PHP脚本需要长时间运行,有的可能会超过10分钟因此我设置了900秒,这样不会导致PHP-CGI死掉而出现502 Bad gateway这个错误。

二、配置 php 慢日志,用于监控

1、开启slow log方法

如果你使用php-fpm来管理php的话,你可以通过如下方法开启:

首先打开 php-fpm.conf 配置文件。

vim /usr/local/php/etc/php-fpm.conf

PHP 5.3.3 之前设置如下:

<value name="request_slowlog_timeout">5s</value>
< value name="slowlog">logs/php-fpm-slowlog.log</value>

PHP 5.3.3 之后设置以下如下:

request_slowlog_timeout = 5s
slowlog = /usr/local/php/var/log/php-fpm-slowlog.log
request_terminate_timeout = 10s

说明:

  • request_slowlog_timeout 是脚本超过多长时间,就可以记录到日志文件;
  • slowlog 是日志文件的存储路径;
  • request_terminate_timeout 将执行时间太长的进程直接终止;

2、slow log使用

开启后,如果有脚本执行超过指定的时间,就会在指定的日志文件中写入类似如下的信息:

[06-Dec-2017 20:05:31]  [pool www] pid 22271
script_filename = /home/wwwroot/default/tz/tz.php
[0x00007f75e662a398] preg_match_all() /home/wwwroot/default/tz/tz.php:453
[0x00007f75e6627f08] sys_linux() /home/wwwroot/default/tz/tz.php:410

由于我把slow log日志放在 /usr/local/php/var/log/php-fpm-slowlog.log 这里,只需要查看此日志即可!

vim /usr/local/php/var/log/php-fpm-slowlog.log

4、slow log 分析

下面是一张日志图片,来做一个简单的分析

说明:

  • script_filename 是入口文件;
  • session_start、session、run、start、sleep : 说明是执行这个方法的时候超过执行时间的。
  • 每行冒号后面的数字是行号。

开启后,在错误日志文件(php-fpm.log)中也有相关记录。如下:

[06-Dec-2017 20:59:53] NOTICE: finished trace of 31450
[06-Dec-2017 20:59:56] WARNING: [pool www] child 31437, script ‘/home/wwwroot/default/tz/tz.php‘ (request: "GET /tz/tz.php") executing too slow (1.047562 sec), logging
[06-Dec-2017 20:59:56] NOTICE: child 31437 stopped for tracing
[06-Dec-2017 20:59:56] NOTICE: about to trace 31437
[06-Dec-2017 20:59:56] NOTICE: finished trace of 31437
[06-Dec-2017 21:00:05] WARNING: [pool www] child 31448, script ‘/home/wwwroot/default/tz/tz.php‘ (request: "GET /tz/tz.php") executing too slow (1.013736 sec), logging
[06-Dec-2017 21:00:05] NOTICE: child 31448 stopped for tracing
[06-Dec-2017 21:00:05] NOTICE: about to trace 31448
[06-Dec-2017 21:00:05] NOTICE: finished trace of 31448
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31481, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.134845 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31478, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.169301 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31475, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.009847 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31468, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.019848 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31455, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.147848 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31451, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.076841 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31447, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.119846 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31443, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.177849 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31436, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.092818 sec), logging
[06-Dec-2017 21:00:10] WARNING: [pool www] child 31433, script ‘/home/wwwroot/default/TTTTT_GAME/index.php‘ (request: "GET /TTTTT_GAME/index.php") executing too slow (1.162842 sec), logging
[06-Dec-2017 21:00:10] NOTICE: child 31433 stopped for tracing
[06-Dec-2017 21:00:10] NOTICE: about to trace 31433
[06-Dec-2017 21:00:10] ERROR: failed to ptrace(PEEKDATA) pid 31433: Input/output error (5)
[06-Dec-2017 21:00:10] NOTICE: finished trace of 31433
[06-Dec-2017 21:00:10] NOTICE: child 31436 stopped for tracing
[06-Dec-2017 21:00:10] NOTICE: about to trace 31436

三、配置 php-fpm 进程可打开的最大文件句柄数

rlimit_files = 1024

默认1024,此值可以不需要配置

四、php-fpm占用cpu和内存过高100% 解决办法

服务器php-fpm突然占用cpu和内存过高,它的服务器配置是4核8G内存。由于php-fpm占用cpu过高从而导致经常出现“502 Bad gateway”。

服务器环境:LNMP一键安装包,

用了“雅黑探针”来查看服务器的性能情况,结果如下:

当然,除了用探针之外,如果你在服务器下用系统命令:top也是可以查看的:

1、CPU 指标解释

Cpu(s): 0.0%us, 0.5%sy, 0.0%ni, 99.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st

  • us:用户空间占用CPU百分比
  • sy:内核空间占用CPU百分比
  • ni:用户进程空间内改变过优先级的进程占用CPU百分比
  • id:空闲CPU百分比
  • wa:等待输入输出的CPU时间百分比
  • hi:硬件中断
  • si:软件中断
  • st:实时

解决办法如下:

多查看日志,根据日志来做解决,最后就是再查看配置文件,是否需要配置调优?

由于有一些步骤不太好表达出来,大家请简单的看一下逻辑吧,需要你懂很多方面的东西才能够明白它。此文中有链接的地方请大家一定要看一下,否则你是不能够明白的。

2、查看它的php-fpm.conf配置

从上面配置文件可以看出,它采用的是动态,默认的启动进程数是4个,最大的是6个,最小的是4个。

3、查看linux平均负载

从上面可以看出,6 个 php-fpm 进程占用的 cpu 空间都很高,平均负载(load average)情况如下:

1分钟平均负载:2.32;

5分钟平均负载:2.18;

15分钟平均负载:3.95;

可以说它现在的平均负载接近了它的cpu总核数:4;需要考虑服务器配置升级!

4、Linux 平均负载 Load Average

1、 Load Average

系统负载(System Load)是系统CPU繁忙程度的度量,即有多少进程在等待被CPU调度(进程等待队列的长度)。

平均负载(Load Average)是一段时间内系统的平均负载,这个一段时间一般取1分钟、5分钟、15分钟。

2、查看Load Average

top命令,w命令,uptime等命令都可以查看系统负载;

3、Load Average 的3个数值说明

我拿上图中的 load average:1.97,2.14,2.99 来举例:

  • 第一位1.97:表示最近1分钟平均负载
  • 第二位2.14:表示最近5分钟平均负载
  • 第三位2.99:表示最近15分钟平均负载

4、Load Average 值的含义

1、单核处理器

(例如:1个1核cpu)

假设我们的系统是单CPU单内核的,把它比喻成是一条单向马路,把CPU任务比作汽车。

当车不多的时候,load <1;

当车占满整个马路的时候 load=1;

当马路都站满了,而且马路外还堆满了汽车的时候,load>1;

2、多核处理器

(例如:2个cpu或一个2核的cpu)

我们经常会发现服务器Load > 1但是运行仍然不错,那是因为服务器是多核处理器(Multi-core)。

假设我们服务器一个CPU是2核,那么将意味我们拥有2条马路,我们的Load = 2时,所有马路都跑满车辆。

提示:

芯片厂商往往在一个CPU内部,包含多个CPU核心,这被称为多核CPU。

在系统负荷方面,多核CPU与多个CPU效果类似,所以考虑系统负荷的时候,必须考虑这台电脑有几个CPU、每个CPU有几个核心。然后,把系统负荷除以总的核心数,只要每个核心的负荷不超过1.0,就表明电脑正常运行。

3、查看服务器 cpu 信息

cat /proc/cpuinfo

4、查看服务器 cpu 总核心数

grep ‘model name‘ /proc/cpuinfo | wc -l 
或
grep -c ‘model name‘ /proc/cpuinfo

5、Load Average 警惕值(单核)

Load < 0.7时:系统很闲,马路上没什么车,要考虑多部署一些服务

0.7 < Load < 1时:系统状态不错,马路可以轻松应对

Load == 1时:系统马上要处理不多来了,赶紧找一下原因

Load > 1时:马路已经非常繁忙了,进入马路的每辆汽车都要无法很快的运行

6、Load Average 关键值(单核)

通常我们先看15分钟load,如果load很高,再看1分钟和5分钟负载,查看是否有下降趋势。

1分钟负载值 > 1,那么我们不用担心,但是如果15分钟负载都超过1,我们要赶紧看看发生了什么事情。所以我们要根据实际情况查看这三个值。

现在相信大家都知道,"load average"一共返回三个平均值:1分钟系统负荷、5分钟系统负荷,15分钟系统负荷;

如果只有1分钟的系统负荷大于1.0,其他两个时间段都小于1.0,这表明只是暂时现象,问题不大。

如果15分钟内,平均系统负荷大于1.0(调整CPU核心数之后),表明问题持续存在,不是暂时现象。所以,你应该主要观察"15分钟系统负荷",将它作为电脑正常运行的指标。

7、结合具体情况具体分析(单核)

  • 1分钟Load>1,5分钟Load<1,15分钟Load<1:短期内繁忙,中长期空闲,初步判断是一个“抖动”,或者是“拥塞前兆”
  • 1分钟Load>1,5分钟Load>1,15分钟Load<1:短期内繁忙,中期内紧张,很可能是一个“拥塞的开始”
  • 1分钟Load>1,5分钟Load>1,15分钟Load>1:短、中、长期都繁忙,系统“正在拥塞”
  • 1分钟Load<1,5分钟Load>1,15分钟Load>1:短期内空闲,中、长期繁忙,不用紧张,系统“拥塞正在好转”

184 total :184个总进程数

4 running:4个正在运行的进程数

143 sleeping:180个睡眠的进程数

0 stoppe:0个停止的进程数

0 zombie:0个冻结进程数

5、更改 php-fpm.conf 配置文件 来做调优

由于服务器是8G内存,按理说应该可以启动 200 个左右的 php-fpm 进程,于是我修改如下:

除了以上配置测试了之外,我还把“pm = dynamic”修改成了“pm= static”配置来做测试,结果都不理想,具体结果向下看:

6、再一次查看linux平均负载

从上面配置可以看出来,每一个php-fpm虽然占用的cpu空间少了,但是总量依然还是接近100%。

而且平均负载(load average)情况如下:

1分钟平均负载:289.73;

5分钟平均负载:264.27;

15分钟平均负载:179.20;

可以说它现在的平均负载接远远超过了总cpu核数:4;必须升级服务器配置。

之所以这么高,除了它本身服务器配置跟不上之外,还有一个就是我把pm.max_spare_servers设置成了512,如果一个线程占用20M内存,则需要512*20;而它现在的服务器只有8G内存4核CPU;因此这个负载才能达到了200多。这里也算是测试的一个小失误吧!

正常情况下,一个线程占用内存20~30M,8G内存设置100~200就足够了。

184 total :678个总进程数

4 running:211个正在运行的进程数

143 sleeping:327个睡眠的进程数

0 stoppe:140个停止的进程数

0 zombie:0个冻结进程数

总结:

因为失误测试,我再重新把配置文件修改成:“pm= static”和 "pm.max_children =100",依然cpu和内存还是占用很高,负载非常的高,这完全是没有道理的。

试想一下:一个 4 核 8G 内存的服务器,居然线程设置越大,CPU占用越高(设置在内存最大允许范围),设置越小 CPu 占用越小,这是不正常的。最主要的是,php-fpm线程虽然小,占用cpu空间少了,但是出现502的次数就多了。从而更加说明了目前的服务器目前的配置支撑不了现有的业务。

现在我朋友向总部申请了8核16G内存的服务器,申请成功后,默认开始启动设置的线程是100,最大线程是200;现在已经恢复正常,如下图:

从这里也可以说明,有时候出问题并不是你自己的原因,就是服务器硬件配置跟不上的原因。

相关推荐