高并发下的php.int及PHP-fpm设置

Opcache 的执行流程大致如下,

E390.png

Opcache 的目地是避免重复编译,减少 CPU 和内存开销。

由于这篇文章的本意是想记录以及备注一下开启 opcache 后出现的一些问题,所以这篇文章不会记录如何安装 opcache 以及如何配置,推荐这篇文章大家参考一下就可以了,配置说的都很明确了。

正文

在配置中有 2 个配置很重要,需要重点关注

opcache.validate_timestamps=0;
opcache.revalidate_freq=60;

validate_timestamps 用于验证是否要重新生成缓存脚本, 如果设置为 0(性能最佳),需要手动在每次 PHP 代码更改后手动清除 OPcache。 如果此值为 0,那么 revalidate_freq 将失去作用。

revalidate_freq 用于控制 opcache 多久生成一次缓存字节码,默认 60s。所以一般我们在开发环境中将上面两个值配置为

opcache.validate_timestamps=1;
opcache.revalidate_freq=1;

或者干脆直接关闭 opcache。

上面提到了,如果将 validate_timestamps 配置为 0 以后,我们每次部署 PHP 的时候默认是不会自动生成缓存。这句话其是是不严谨的,因为部署 PHP 的时候有两种方式,一种是直接覆盖就文件,另一种是使用 CI 发布会自动生成新的部署目录,并通过软连接的方式指定到 web 目录

如果是第一种部署方式的话,opcache 确实不会自动生成缓存,因为 opcache 通过文件的真实路径进行缓存,如果文件存在就不会再次缓存,也就导致了部署后线上并没有看到新的功能代码。

而另一种方式的确会主动生成缓存,因为上面说了,opcache 是通过文件的真实路径进行缓存的,这就导致了每次部署都会生成缓存字节码,那么就导致了旧的缓存没有被清理,那么迟早有一天会撑爆内存。

所以,在部署代码的时候如何清理 opcahce 生成的缓存就成为了关键所在。

解决方案

通过搜索实践发现了几种方式,分别为

  1. 平滑重启 php-fpm
  2. 通过 opcache_reset () 函数
  3. 第三方库

平滑重启的方式就类似下面这样,通过部署钩子实现

cd /www/myproject
sudo -u www git reset --hard
sudo -u www git pull origin master
sudo -u root /etc/init.d/php-fpm-73 reload

使用 opcache_reset () 函数需要注意的问题就是在 cli 命令行下执行此函数并不能清理 php-fpm 下生成的缓存字节码,所以可以通过一种曲线救国的方式

curl http://example.com/op.php

这个 op.php 文件里面就专门执行 opcache_reset () 函数,但是这种方式总感觉有点怪怪的。

通过第三方库 (推荐) 的方式,大佬推荐 cachetool

服务器中找到php-fpm.conf配置(有的会在引入的www.conf中)

[global]
pid = /usr/local/php/var/run/php-fpm.pid
error_log = /usr/local/php/var/log/php-fpm.log
log_level = notice

[www]
listen = /tmp/php-cgi.sock
listen.backlog = -1
listen.allowed_clients = 127.0.0.1
listen.owner = www
listen.group = www
listen.mode = 0666
user = www
group = www
pm = static
pm.max_children = 200
pm.start_servers = 40
pm.min_spare_servers = 10
pm.max_spare_servers = 20
pm.max_requests=1000
request_terminate_timeout = 100
request_slowlog_timeout = 0
slowlog = var/log/slow.log
一. pm= static

首先说一下pm这个值 pm = dynamic 这个是php的进程数是动态的 会根据访问量来确定来回增加

而在高负载的php环境下我推荐设置 pm= static php-fpm进程数固定

二. pm.max_children=???

当用静态模式下 进程数确定根据 pm.max_children来进进行确定 那么问题来了我的服务器应该设定多少php-fpm呢 ?

从理论的角度上说php-fpm进程数越多越好,相当于一个酒店有很多个充足的服务员来为你服务肯定会比较爽啊 ,你也不需要等待。

 但是。。。。现实上总是残酷的   php-fpm的进程数会受到你的内存大小的限制。一般情况下我们    进程数 =用机器内存(M)除以2  再除以20(M);

 当然这个也不是绝对的   你需要知道:

你可以分配给php多大内存 :你的服务器上是不是单纯的php服务器 有没有比较耗费内存的其他程序(mysql)。
你的每个php-fpm内存占多大 :内存占用多大要根据你的php代码质量和处理的相关业务。当然你可以用命令去统计你的php-fpm平均占用内存大小。
有人会问我如果设置不恰当会有什么状况出现呢?

   当数值偏小时请求到nginx会无法分配到php-fpm进程 导致502错误

  当数值偏大如果没有大访问量还好 如果访问量较大的话 内存都会被php占光了。导致系统响应缓慢 cpu-system 升高 系统不断的去调整内存分配

      严重时会导致较高的 cup-wait 较高   内存不够用了  直接写磁盘  磁盘io直线增加 。cpu使用率也开始爆满。(如图所示)

三.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.max_requests
这个参数的含义是php-fpm工作进程处理完多少请求后自动重启,主要目的就是为了控制请求处理过程中的内存溢出,使得内存占用在一个可接受的范围内。比较适用于服务器搭载项目比较杂乱,有点请求会比较占用内存

    导致php-fpm占用比较大。在经过一定次数请求后会结束掉进程,释放自己的内存。如果这个值太小就会导致所有的工作进程几乎同时达到这个值并且进入需要重启的状态,当所有的工作进程都在同一时刻重启就会发生在

  数秒内甚至更长的时间PHP将停止响应直到所有的进程均重启完为止。这是不能接受的,所以我一般会把这个值设置为PHP启动后第一批工作进程达到此值需要重启时,第一个进程重启与最后一个进程重启之间的时间相差

  1分钟以上,一般在压力比较大的晚上这个差值将会扩大到5分钟左右,此时对进程重启对服务器的负面影响就可以忽略了。

  下面补充几个命令统计相关php-fpm 相关数据

1、查看php-fpm的进程个数

ps -ef |grep “php-fpm”|grep “pool”|wc -l
2、查看每个php-fpm占用的内存大小

ps -ylC php-fpm –sort:rss
3.查看PHP-FPM在你的机器上的平均内存占用

ps –no-headers -o “rss,cmd” -C php-fpm | awk ‘{ sum+=$1 } END { printf (“%d%s\n”, sum/NR/1024,”M”) }’
4.查看单个php-fpm进程消耗内存的明细

pmap $(pgrep php-fpm) | less

本作品采用《CC 协议》,转载必须注明作者和本文链接
你还差得远呐!
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!