最近服务器经常发现php-fpm进程cpu总数时不时就100%,提高cpu核数也还是一样
废话不多说,直接说解决方案:
一、先说说php-fpm三种子进程的管理方式
pm = static
静态,始终保持一个固定数量的子进程,这个数由(pm.max_children)定义,这种方式很不灵活,也通常不是默认的。
pm = dynamic
动态,在更老一些的版本中,dynamic被称作apache-like。子进程的数量在下面配置的基础上动态设置:pm.max_children,pm.start_servers,pm.min_spare_servers,pm.max_spare_servers。
启动时,会产生固定数量的子进程(由pm.start_servers
控制)可以理解成最小子进程数,而最大子进程数则由pm.max_children
去控制,OK,这样的话,子进程数会在最大和最小数范围中变化,还没有完,闲置的子进程数还可以由另2个配置控制,分别是pm.min_spare_servers
和pm.max_spare_servers
,也就是闲置的子进程也可以有最小和最大的数目,而如果闲置的子进程超出了pm.max_spare_servers
,则会被杀掉。
可以看到,pm = dynamic
模式非常灵活,也通常是默认的选项。但是,dynamic
模式为了最大化地优化服务器响应,会造成更多内存使用,因为这种模式只会杀掉超出最大闲置进程数(pm.max_spare_servers
)的闲置进程,比如最大闲置进程数是30,最大进程数是50,然后网站经历了一次访问高峰,此时50个进程全部忙碌,0个闲置进程数,接着过了高峰期,可能没有一个请求,于是会有50个闲置进程,但是此时php-fpm
只会杀掉20个子进程,始终剩下30个进程继续作为闲置进程来等待请求,这可能就是为什么过了高峰期后即便请求数大量减少服务器内存使用却也没有大量减少,也可能是为什么有些时候重启下服务器情况就会好很多,因为重启后,php-fpm
的子进程数会变成最小闲置进程数,而不是之前的最大闲置进程数。
pm = ondemand
进程在有需求时才产生,与 dynamic 相反,pm.start_servers 在服务启动时即启动。
这种模式把内存放在第一位,他的工作模式很简单,每个闲置进程,在持续闲置了pm.process_idle_timeout
秒后就会被杀掉,有了这个模式,到了服务器低峰期内存自然会降下来,如果服务器长时间没有请求,就只会有一个php-fpm
主进程,当然弊端是,遇到高峰期或者如果pm.process_idle_timeout
的值太短的话,无法避免服务器频繁创建进程的问题,因此pm = dynamic
和pm = ondemand
谁更适合视实际情况而定。
涉及到的参数:
- pm.max_children:静态方式下开启的php-fpm进程数量。
- pm.start_servers:动态方式下的起始php-fpm进程数量。
- pm.min_spare_servers:动态方式下的最小php-fpm进程数量。
- pm.max_spare_servers:动态方式下的最大php-fpm进程数量。
如果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进程数。
二、php-fpm各个参数的设置
pm.max_children 设置多大合适?
php-fpm.conf有两个至关重要的参数:
一个是”max_children”,另一个是”request_terminate_timeout”。
pm.max_children 表示 php-fpm 能启动的子进程的最大数量。
request_terminate_timeout 表示将执行时间太长的进程直接终止。
我的两个设置的值一个是”40″,一个是”900″,但是这个值不是通用的,而是需要自己计算的。(后面再讲具体怎么计算)
1、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比较好,这是动态来调整的。
2、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这个错误。
#############################################################################
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 来计算。
如果dm设置为static,那么其实只有pm.max_children这个参数生效。系统会开启设置数量的php-fpm进程。
如果dm设置为dynamic,那么pm.max_children参数失效,后面3个参数生效。系统会在php-fpm运行开始的时候启动pm.start_servers个php-fpm进程,然后根据系统的需求动态在pm.min_spare_servers和pm.max_spare_servers之间调整php-fpm进程数。
如何判断我选择“pm = dynamic”还是“pm = static”呢?哪一种更好呢?
事实上,跟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)。
配置php慢日志,用于监控
request_slowlog_timeout = 10s
slowlog = log/$pool.log.slow
配置php-fpm进程可打开的最大文件句柄数,
rlimit_files = 1024
默认1024,此值可以不需要配置
三、计算方式总结
在浏览了各种讨论和博客文章后,我设法拼凑出以下信息。
在更改 PHP FPM 的设置之前,您需要了解有关服务器的三件事。
- 您的服务器有多少个核心?
- 服务器上的内存 (RAM) 量。
- 您的服务器上的 PHP 进程平均消耗多少内存?
1. 您的服务器有多少个核心?
要了解您的服务器有多少个核心,请运行以下命令:
echo 核心 = $(( $(lscpu | awk '/^Socket/{ print $2 }') * $(lscpu | awk '/^Core/{ print $4 }') ))
当您运行上面的 Linux 命令时,您将得到类似“核心 = 4”的信息。
写下这个数字,因为它很重要。
2. 您的服务器有多少内存?
您应该已经知道您的服务器有多少内存。
这里真正的问题是:您想给 PHP 多少内存?
您必须考虑到您的服务器可能还运行 NGINX、Apache 或 MySQL。这些其他进程消耗了多少内存?如果您有 8GB RAM,而计算机上的其他进程正在消耗 2GB,那么您还剩下 6GB。
如果您想安全起见并留出一些免费空间,则可以选择 5GB。
确定您想要为 PHP 提供多少内存并将其记下来。就我而言,我有 4GB 可以分配给 PHP。
3.平均每个 PHP 进程消耗多少内存?
这取决于您的应用程序和 PHP 版本。较旧版本的 PHP 往往比 PHP 7 消耗更多内存。
运行以下命令以大致了解每个 PHP FPM 进程消耗了多少内存。
ps --no-headers -o "rss,cmd" -C php-fpm | ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"M") }'
请注意,上面的命令正在寻找名为 php-fpm 的进程。您服务器上的 PHP 进程可能有不同的名称。
要查找 PHP 进程的名称,请使用top命令。当您运行 top 命令时,您可能会看到以下进程之一:
- php-fpm
- php5-fpm
- php7.0-fpm
- php7.1-fpm
- php7.2-fpm
当我运行上面的命令时,我得到了 29M。
换句话说,我的服务器上的每个 php-fpm 进程消耗大约 29MB 的 RAM。
4. 配置设置。
我现在掌握了三项重要信息。
- 我的服务器有 4 个核心。
- 我可以为 PHP 分配大约 4GB 的 RAM。
- 我的服务器上的每个 PHP FPM 进程消耗大约 29MB 内存。在旧版本的 PHP 上,您可能会发现每个进程的消耗量远不止于此。当我在 PHP 5.5 上运行完全相同的应用程序时,每个进程的内存达到了大约 90MB。
现在是时候编辑php-fpm的配置的,我是用宝塔,位置在
“软件商店”选择对应php版本->“设置”->FPM配置文件
在您的计算机上,该位置可能略有不同。
我们要在配置文件中更改 4 个配置值:
- pm.max_children
- pm.start_servers
- pm.min_spare_servers
- pm.max_spare_servers
pm.max_children
为了获得一个好的值,您应该将要分配给 PHP FPM 的内存除以每个 PHP FPM 进程消耗的平均内存。
就我而言,我想分配 4GB (4000MB),每个进程消耗大约 29MB。
将 4000 除以 29,大约得到 138。
所以我将pm.max_children设置为 138。
如果您有 8000MB 的空闲空间,并且您的 PHP 每个进程消耗大约 80MB,那么这将是:8000 / 80 = 100。
pm.start_servers
对于 pm.start_servers,我将拥有的核心数乘以 4。
4 x 4 = 16
所以我将pm.start_servers设置为 16。
如果您有 8 个核心,则将为:4 x 8 = 32。
pm.min_spare_servers
对于 pm.min_spare_servers,将您拥有的核心数乘以 2。
就我而言,即 2 x 4 = 8。
所以我将pm.min_spare_servers设置为 8。
pm.max_spare_servers
对于 pm.max_spare_servers,请将服务器上的核心数乘以 4。
在我的机器上,即 4 x 4 = 16。
因此,我将pm.max_spare_servers设置为 16,与我用于 pm.start_servers 的值相同。
5. 重新启动 PHP FPM。
为了使这些更改生效,您需要重新启动 PHP FPM。
我是宝塔 直接
“软件商店”选择对应php版本->“设置”->“服务”->“重启”四、总结
pm=dynamic; //弹性,兼顾性能与内存情况,不知道怎么设置的可以选择这个,但是比较复杂要根据上面的计算,配置好各个参数值 pm = ondemand; //省内存,耗性能,适用于内存不足的情况 pm = static ; //性能高,耗内存,适用于内存充足且对性能要求比较高的情况 根据以上信息,结合我的服务器的业务情况,我原本配置的是pm = ondemand,所以经常出现cpu100%的情况,后面查看了下,我内存充足,才用20%左右,而且目前对性能要求也比较高,于是我选择了 pm = static 配置好之后,明显cpu下降到了不到20%,内存也还是20%多一点而已
来源地址:https://blog.csdn.net/weixin_44052462/article/details/131850309