如何为多个PHP-FPM容器构建单一的Nginx Docker镜像

在使用 Docker 容器来开发 PHP 微服务套件的过程中,作者遇到了容器数量过多的问题。

最近,我一直在使用 Docker 容器来开发 PHP 微服务套件。一个问题是 PHP 应用已经搭建,可以与 PHP-FPM 还有 Nginx(取代了简单的 Apche/PHP 环境)一起工作,因此每个 PHP 微服务需要两个容器(以及两个 Docker 镜像):一个 PHP-FPM 容器和一个 Nginx 容器。
这个应用运行了 6 个以上的服务,做个乘法就知道,在开发和生产之间会有约 30 个容器。于是我决定构建一个单独的 Nginx Docker 镜像,它可以使用 PHP-FPM 的主机名作为环境变量并运行单独的配置文件,而不用为每个容器构建单独的 Nginx 镜像。

未分类

在本文中,我介绍了自己从上图中的方法 1 到方法 2 的转换,最后采用的方案中采用了一种新的定制 Docker 镜像。该镜像的代码是开源的,如果读者碰到类似问题,可以提供给大家参考。

为什么用 Nginx?

Nginx 和 PHP-FPM 配合使用能使 PHP 应用的性能更好,但不好的地方在于,和 PHP Apache 镜像不同,PHP-FPM Docker 镜像默认不是和和 Nginx 绑定在一起的。如果需要通过 Nginx 容器和 PHP-FPM 连接,需要在 Nginx 配置里为该后端增加 DNS 记录。比如,如果名为 php-fpm-api 的 PHP-FPM 容器正在运行,Nginx 配置文件应该包含下面部分:

location ~ .php$ {
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        # This line passes requests through to the PHP-FPM container
        fastcgi_pass php-fpm-api:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

如果只服务于单独的 Nginx 容器,Nginx 配置中容器名字写死还可以接受,但如上所述,需要允许多个 Nginx 容器,每个对应于一个 PHP 服务。创建一个新的 Nginx 镜像(以后需要进行维护和升级)会有些痛苦,即使管理一批不同的数据卷,仅仅改变变量名看起来也有很多工作。

第一种方案: 使用 Docker 文档中的方法

最初,我认为这会很简单。Docker 文档中有少许的几个章节讨论如何使用 envsubst 来完成该工作,但不幸的是,在我的 Nginx 配置文件中,这种方法不奏效。

vhosts.conf

server {
    listen 80;
    index index.php index.html;
    root /var/www/public;
    client_max_body_size 32M;
    location / {
        try_files $uri /index.php?$args;
    }
    location ~ .php$ {
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass ${NGINX_HOST}:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

该vhosts.conf文件使用了 Nginx 内置变量,因此当依照文档运行 Docker 命令 (/bin/bash -c “envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g ‘daemon off;’”) 时,得到错误提示$uri和$fastcgi_script_name没有定义。这些变量通常通过 Nginx 传入,因此不能简单的识别出他们是什么并传给自身,而且这样会影响容器的动态配置。

使用另一个 Docker 镜像,差点成功

接下来,我开始研究不同的 Nginx 镜像。找到的有两个,但它们都在随后的几年中都没有任何更新。我开始使用 martin/nginx,试图找到可以工作的原型。

Martin 的镜像和其它镜像有点不一样,因为它要求特定的文件夹结构。在 root 下增加Dockerfile:

FROM martin/nginx

接下来,我添加了一个app/空目录和conf/目录,conf/目录下只有一个文件
vhosts.conf:

server {
    listen 80;
    index index.php index.html;
    root /var/www/public;
    client_max_body_size 32M;
    location / {
        try_files $uri /index.php?$args;
    }
    location ~ .php$ {
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass $ENV{"NGINX_HOST"}:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

这个文件和之前的配置文件几乎一样,除了有一行的改动:
fastcgi_pass $ENV{“NGINX_HOST”}:9000;。现在想要启动带命名为 php-fpm-api 的 PHP 容器的 Nginx 容器,就可以构建一个新的镜像,让它在以下环境变量下运行:

docker build -t shiphp/nginx-env:test .
docker run -it --rm -e NGINX_HOST=php-fpm-api shiphp/nginx-env:test

它可以正常工作了。但是,这种方法有两个困扰的地方:
正在使用的基础镜像已经有两年了。这会引入安全和性能风险。
有个空的/app目录看起来并不必需,因为文件会被存储在一个不同的目录中。

最终解决方案

我认为作为定制解决方案,从 Martin 镜像开始比较好,因此我给项目建了分叉,创建了新的 Nginx 基础镜像并修复了上述两个问题。现在,如果要在 Nginx 容器中允许动态命名的后端,可以参照:

# 从 Docker Hub 得到最新版本
docker pull shiphp/nginx-env:latest
# 运行名为"php-fpm-api"的 PHP 容器 
docker run --name php-fpm-api -v $(pwd):/var/www php:fpm
# 允许链接到 PHP-FPM 容器的 NGinx 容器
docker run --link php-fpm-api -e NGINX_HOST=php-fpm-api shiphp/nginx-env

如果想增加自己的文件或 Nginx 配置文件,来定制镜像,用Dockerfile来扩展它就可以:

FROM shiphp/nginx-env
ONBUILD ADD <PATH_TO_YOUR_CONFIGS> /etc/nginx/conf.d/
...

现在所有的 PHP-FPM 容器都能使用单个Docker镜像中自己的实例,这样在升级 Nginx,改变权限或做某些调整时,就变得非常轻松了。

所有的代码都在 Github 上,如果你看到任何问题或有改进建议,可以直接创建 issue。

GitHub 项目链接:https://github.com/shiphp/nginx-env

CENTOS 7上PHP-FPM无法启动的问题处理

缘由:

现在自用的Linux主机系统我都是选的CentOS 7,用的PHP版本也升级到了PHP 7。在之前的主机、博客维护过程中已经出过不少问题,这次又碰到了一个问题——在主机因维护而重启后php-fpm没有正确启动导致博客无法正常访问,解决办法和之前的不太一样,所以在此记录一下,方便以后查阅、参考。

正文:

参考解答:

0、一些辅助命令

# ls -lt /etc/systemd/system/multi-user.target.wants/

# find / -type f -iname "php-fpm.conf" | xargs ls -lt
# grep -v '^;' /etc/opt/remi/php71/php-fpm.d/www.conf | grep 'listen'

# nginx -t
# grep "fastcgi_pass" /etc/nginx/nginx.conf

1、systemd的系统启动项

应该是从CentOS 7开始,Linux服务管理器开始用systemd来替换之前的SysVinit,很多命令和之前不太一样,具体的可以参考之前记录的一篇文章「Linux的systemd相关知识学习」,这里只提一点:

# systemd里面的.service文件一般是放在下面这个目录下,当不记得服务名称了,可以去目录里看看
# ls -lt /usr/lib/systemd/system/
# cat /usr/lib/systemd/system/php71-php-fpm.service

&

# 查看当前系统上现在有哪些开机启动项,如果不在的话使用enable进行添加
# ls -lt /etc/systemd/system/multi-user.target.wants/
# systemctl enable nginx
# systemctl enable php71-php-fpm
# systemctl enable mysqld

2、php-fpm启动失败的原因

● php71-php-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php71-php-fpm.service; disabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since Wed 2018-05-05 10:38:32 CST; 36s ago
  Process: 5500 ExecStart=/opt/remi/php71/root/usr/sbin/php-fpm --nodaemonize (code=exited, status=78)
 Main PID: 5500 (code=exited, status=78)

May 05 10:38:32 ixyzero-centos systemd[1]: Starting The PHP FastCGI Process Manager...
May 05 10:38:32 ixyzero-centos php-fpm[5500]: [02-May-2018 10:38:32] ERROR: unable to bind listening socket for address '/var/run/php-fpm/php-fpm.sock': No such file or directory (2)
May 05 10:38:32 ixyzero-centos php-fpm[5500]: [02-May-2018 10:38:32] ERROR: FPM initialization failed
May 05 10:38:32 ixyzero-centos systemd[1]: php71-php-fpm.service: main process exited, code=exited, status=78/n/a
May 05 10:38:32 ixyzero-centos systemd[1]: Failed to start The PHP FastCGI Process Manager.
May 05 10:38:32 ixyzero-centos systemd[1]: Unit php71-php-fpm.service entered failed state.
May 05 10:38:32 ixyzero-centos systemd[1]: php71-php-fpm.service failed.

即,没有 /var/run/php-fpm/php-fpm.sock 这个文件,导致无法绑定监听端口/文件,初始化失败。

之前出现这种问题,一般是以下原因之一:

  • php-fpm的配置文件里的listen.owner/group和Nginx配置文件里的user/group不匹配,导致权限不够;
  • php-fpm的配置文件里的listen和Nginx配置文件里的fastcgi_pass不匹配,导致监听和读取的不是同一个socket文件;

3、临时解决办法

但这次不是,这次的上面2个配置都是对的,但就是 /var/run/php-fpm/php-fpm.sock 这个文件不存在,解决办法也很简单,就是:

# sudo mkdir -p /var/run/php-fpm/
# sudo touch /var/run/php-fpm/php-fpm.sock

# sudo systemctl start php71-php-fpm

不过,一旦机器重启,/var/run/php-fpm/php-fpm.sock 这个文件就又没了,而且 /var/run/php-fpm/ 这个目录也没了,所以,这种手工创建目录、文件的方式只能临时生效。

4、长期解决办法

如果想要找到一个长期有效的办法,那就需要定位问题以及其背后的原因,否则问题还是会一直存在。

# 看 /var/run/ 目录权限
[zero@ixyzero-centos ~]$ ls -lt /var/ | grep "run"
lrwxrwxrwx.  1 root root   11 2月   3 2017 lock -> ../run/lock
lrwxrwxrwx.  1 root root    6 2月   3 2017 run -> ../run
[zero@ixyzero-centos ~]$
[zero@ixyzero-centos ~]$ ls -lt / | grep "run"
drwxr-xr-x  22 root root   620 5月   2 16:30 run

# 从上面的信息可以看出, /var/run 这个目录只有root才有「写」权限,而php-fpm的执行用户是和Nginx一样的低权限用户,所以无法创建 /var/run/php-fpm/ 子目录,从而也就无法创建 /var/run/php-fpm/php-fpm.sock 文件

# 目录 /var/run 有点「内存盘」的感觉,就是说它不是一直稳定存在的,而是只存在于内存中(网上有说法是这样会提高速度),当系统重启时,/var 下的目录便会消失,需要重新创建

综上,我将原先php-fpm的配置文件里的listen和Nginx配置文件里的fastcgi_pass都改成了 /var/run/php-fpm.sock ,然后将php-fpm和Nginx服务都加入系统启动项,重启系统,一切OK。

LNMP架构 (6) 之 php-fpm的pool、慢执行日志、open_basedir、进程管理

1. php-fpm的pool

为了避免因多站点使用同一个pool时,因为一个站点故障导致pool出问题,进而影响使用同一个pool的其他站点的正常运行,我们有必要对每一个站点设置一个单独的pool。

1.1 为php-fpm配置多个pool

编辑php-fpm配置文件:

[root@host etc]# vim /usr/local/php-fpm/etc/php-fpm.conf  

[www]
listen = /tmp/php-fcgi.sock
#listen = 127.0.0.1:9000
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
……
[zhouqun.com]      //添加新的pool
listen = /tmp/zhouqun.sock
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024

1.2 语法检测

[root@host etc]# /usr/local/php-fpm/sbin/php-fpm -t
[12-Sep-2017 23:26:57] NOTICE: configuration file /usr/local/php-fpm/etc/php-fpm.conf test is successful

1.3 重新加载配置文件

[root@host etc]# /etc/init.d/php-fpm reload
Reload service php-fpm  done

1.4 查看进程

[root@host etc]# ps aux |grep php-fpm

php-fpm  6222  0.0  0.4 226640  4716 ?        S    16:10  0:00 php-fpm: pool www
php-fpm  6223  0.0  0.4 226640  4712 ?        S    16:10  0:00 php-fpm: pool zhouqun.com

1.5 为站点设置pool

[root@host vhost]# vim /usr/local/nginx/conf/vhost/aaa.com.conf

location ~ .php$
    {
        include fastcgi_params;
        fastcgi_pass unix:/tmp/zhouqun.sock;    //把fastcgi_pass地址改为和php-fpm.conf中一样的地址就可以
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /data/wwwroot/default$fastcgi_script_name;
    }

1.6 添加php-fpm.conf子配置文件

为了便于管理,可以将php-fpm中的每个pool单独进行管理。进行如下操作,添加php-fpm子配置文件:

[root@host vhost]# vim /usr/local/php-fpm/etc/php-fpm.conf

[global]
pid = /usr/local/php-fpm/var/run/php-fpm.pid
error_log = /usr/local/php-fpm/var/log/php-fpm.log
include = etc/php-fpm.d/*.conf   //添加
#在全局变量版块添加参数“include = etc/php-fpm.d/*.conf”。然后可以清除php-fpm配置文件中其他参数,再到php-fpm.d目录下进行单独设置。

1.7 创建指定目录

[root@host vhost]# cd /usr/local/php-fpm/etc/
[root@host etc]# mkdir php-fpm.d

[root@host etc]# cd php-fpm.d/

1.8 创建php-fpm子配置文件

[root@host php-fpm.d]# vim www.conf
[www]
listen = /tmp/php-fcgi.sock
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024

[root@host php-fpm.d]# vim zhouqun.conf
[zhouqun.com]
listen = /tmp/zhouqun.sock
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024

1.9 检查语法错误并重启:

[root@host php-fpm.d]# /usr/local/php-fpm/sbin/php-fpm -t
[16-Aug-2017 16:49:17] NOTICE: configuration file /usr/local/php-fpm/etc/php-fpm.conf test is successful

[root@host php-fpm.d]# /etc/init.d/php-fpm reload
Reload service php-fpm  done

查看php-fpm进程信息还是使用ps命令。

2. php-fpm慢执行日志

php网站莫名的访问很慢,可以通过慢执行日志找到症结所在,所以满日志非常重要,php网站强烈推荐使用LNMP架构搭建。

2.1 开启慢执行日志:

[root@host php-fpm.d]# vim /usr/local/php-fpm/etc/php-fpm.d/www.conf
……
request_slowlog_timeout = 1                //当请求超过1秒开始记录日志
slowlog = /usr/local/php-fpm/var/log/www-slow.log           //日志存放地址
检测并重加载
[root@host php-fpm.d]# /usr/local/php-fpm/sbin/php-fpm -t
[root@host php-fpm.d]# /etc/init.d/php-fpm reload

2.2 试验

在使用www pool的站点添加文件:

[root@host php-fpm.d]# vim /data/wwwroot/test.com/sleep.php   //创建一个.php文件,故意让它休眠2秒,让它运行缓慢
<?php
echo "test slow log";
sleep(2);     
echo "done";
?>

2.3 检测

[root@host php-fpm.d]# curl -x127.0.0.1:80 test.com/sleep.php 
test slow log done

2.4 查看慢日志

[root@host php-fpm.d]# tail /usr/local/php-fpm/var/log/www-slow.log 

[12-Sep-2017 23:42:23]  [pool www] pid 4236
script_filename = /data/wwwroot/test.com/sleep.php
[0x00007fe027r0e2f5] sleep() /data/wwwroot/test.com/sleep.php:3      //显示文件的第三行导致的访问慢,因为第三行就是sleep命令

3. php-fpm定义open_basedir

在php-fpm服务中,当一台服务器跑多个网站时,用open_basedir限定各个站点所能访问的服务器上的目录的范围,可以针对每个pool设定open _ basedir。

3.1 核心配置参数:

[root@host ~]# vim /usr/local/php-fpm/etc/php-fpm.d/www.conf  
……
php_admin_value[open_basedir]=/data/wwwroot/test.com:/tmp/     //修改

3.2 创建测试PHP脚本

[root@host php-fpm.d]# vim /data/wwwroot/test.com/1.php
<?php
echo "This is a test php of open_basedir";

3.3 测试

[root@host php-fpm.d]# curl -x127.0.0.1:80 test.com/1.php
This is a test php of open_basedir

4. php-fpm进程管理

php-fpm中pool配置参数解析:

[root@host php-fpm.d]# vim www.conf
[www]
listen = /tmp/php-fcgi.sock
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
#设置进程启动方式(dynamic表示动态,static表示静态)
#只有此处设置为dynamic,下面的配置才生效
pm.max_children = 50   //最多可启动的子进程数量
pm.start_servers = 20    //设定初始启动的进程数量
pm.min_spare_servers = 5      //表示php-fpm空闲时最少要有几个子进程
pm.max_spare_servers = 35   //表示php-fpm空闲时最多要有几个子进程
pm.max_requests = 500          //表示一个子进程最多可接受多少个请求
rlimit_files = 1024                     //表示每个子进程打开的多少个文件句柄
request_slowlog_timeout = 1    //当请求超过1秒开始记录日志
slowlog = /usr/local/php-fpm/var/log/www-slow.log      //日志存放地址
php_admin_value[open_basedir]=/data/wwwroot/test.com:/tmp/

解决Linux中PHP-FPM进程过量占用内存

1. 事情经过

其实这个问题困扰了我很长时间。事情经过是这样的:我在写这篇文章前几天,对网站服务器进行了停机维护,其中包括更换操作系统、重新配置网站环境、更换博客程序、使用新模板等许多操作(包括误删数据库并没有)。然后问题就出现了!内存多次跑满(如图)!由于我在服务器商处设置了内存超量报警,导致收到了几十条报警信息。由于我这几天有些事情(因为懒并不是),没有认真打理网站,所以只是确定服务器未被入侵后就重启了之。这一拖就到了今天。但是问题早晚要解决!现在我们来解决这个问题吧。

未分类

2. 排查过程

实际上排查还是很简单的,直接使用 linux 自带的命令free -m 然后查看空闲内存确定是内存跑满,然后是使用top命令查看进程情况,并确定 cpu 状态正常。

(这里本应有一张我修复故障前的 top 命令结果图,但是我忘记截图了……)

查询结果可以看见我服务器中PHP-FPM进程占用了一半多的内存,找到原因,果断处理!

补充几条命令,会对你排错有帮助:

查看每个PHP-FPM进程的内存占用:ps -ylC php-fpm –sort:rss

查看消耗内存最多的前 40 个进程:ps auxw|head -1;ps auxw|sort -rn -k4|head -40

查看PHP-FPM的平均内存占用:ps –no-headers -o “rss,cmd” -C php-fpm | awk ‘{ sum+=$1 } END { printf (“%d%sn”, sum/NR/1024,”M”) }’

3. 处理方法

我们可以通过修改 php 的配置文件来限制PHP-FPM的创建和销毁。

我们找到 /www/server/php/etc/php-fpm.conf (在我服务器中是这个路径) 文件,用 vi 打开,找到 pm.max_children 也就是控制 php-fpm 子进程数量的字段,我修改前这个字段是 50,我将其修改为 25。再找到pm.max_spare_servers 这个字段表示空闲进程数的最大值,这个数应为pm.max_children 的 60%~80%,所以我设置为 17。

注意:如果pm.max_children设置过小可能会导致 502 错误频发,应按照自己服务器业务要求和服务器能力自行设置!

这样我们就修改好了配置文件 :wq 退出 vi,并使用 systemctl restart php-fpm 重启PHP-FPM。

未分类

(我基本可以确定,90%用户的php-fpm.conf文件与上图不同,大家自己找对应字段就好

4. 处理结果

我们可以看到重启服务后内存瞬间降低至 26%然后稳定到 50%,所以这个问题算是解决了!

未分类

php-fpm启动,重启,终止操作方法

启动php-fpm

/usr/work/php/sbin/php-fpm

php5.3.3以后的版本不在支持这种方式,需要以信号方式控制

INT, TERM 立刻终止
QUIT 平滑终止
USR1 重新打开日志文件
USR2 平滑重载所有worker进程并重新载入配置和二进制模块php-fpm master进程可以理解以下信号

先查看php-fpm的master进程号

未分类

kill -USR2 10856    

就直接平滑重启php-fpm了

但是如果生成php-fpm.pid,重启时可以使用下面这种方案:

上面master进程可以看到,matster使用的是/usr/work/tool/php/etc/php-fpm.conf这个配置文件,cat /usr/work/tool/php/etc/php-fpm.conf 发现:

未分类

pid文件路径应该位于/usr/work/tool/php/etc/php-fpm.conf,由于注释掉,所以没有生成,我们把注释去除,再kill -USR2 10856 重启php-fpm,便会生成pid文件,下次就可以使用以下命令重启,关闭php-fpm了:

php-fpm 关闭:

kill -INT `cat /usr/work/tool/php/var/run/php-fpm.pid`

php-fpm 重启:

kill -USR2 `cat /usr/work/local/php/var/run/php-fpm.pid`

php-fpm进程过多,内存耗尽

重拾博客,在启用伪静态等加速技术后,服务器mysql数据库频繁出现宕机现象。

未分类

输入命令top查看进程后,发现php-fpm占用多达20个进程,每个进程占用内存4%,使得mysql因为内存耗尽而停止。在改动php-fpm后,问题迎刃而解。

一、内存耗尽解决方案

找到php-fpm.conf,该配置文件与php.ini一起在php的文件夹下。

我所在的目录是 /usr/local/php54/etc/php-fpm.conf

找到如下设置:

未分类

由于我所使用的服务器为1G内存的,故改为如上设置

二、php-fpm参数概述

下面对每个参数的意义进行简要的概述分析

pm=dynamic

该项共有三种设置方式 static 、 dynamic 、ondemand

  • 一种是pm = static,始终保持一个固定数量的子进程,这个数由pm.max_children定义,这种方式很不灵活,也通常不是默认的。

  • 另一种是pm = dynamic,他是这样的,启动时,会产生固定数量的子进程(由pm.start_servers控制)可以理解成最小子进程数,而最大子进程数则由pm.max_children去控制,这样的话,子进程数会在最大和最小数范围中变化,还没有完,闲置的子进程数还可以由另2个配置控制,分别是pm.min_spare_servers和pm.max_spare_servers,也就是闲置的子进程也可以有最小和最大的数目,而如果闲置的子进程超出了pm.max_spare_servers,则会被杀掉。(注意,pm.max_spare_servers应小于pm.max_children)

  • 第三种就是pm = ondemand模式,这种模式和pm = dynamic相反,把内存放在第一位,他的工作模式很简单,每个闲置进程,在持续闲置了pm.process_idle_timeout秒后就会被杀掉,有了这个模式,到了服务器低峰期内存自然会降下来,如果服务器长时间没有请求,就只会有一个php-fpm主进程,当然弊端是,遇到高峰期或者如果pm.process_idle_timeout的值太短的话,无法避免服务器频繁创建进程的问题,因此pm = dynamic和pm = ondemand谁更适合视实际情况而定。

可以看到,pm = dynamic模式非常灵活,也通常是默认的选项。但是,dynamic模式为了最大化地优化服务器响应,会造成更多内存使用,因为这种模式只会杀掉超出最大闲置进程数(pm.max_spare_servers)的闲置进程,比如最大闲置进程数是30,最大进程数是50,然后网站经历了一次访问高峰,此时50个进程全部忙碌,0个闲置进程数,接着过了高峰期,可能没有一个请求,于是会有50个闲置进程,但是此时php-fpm只会杀掉20个子进程,始终剩下30个进程继续作为闲置进程来等待请求,这可能就是为什么过了高峰期后即便请求数大量减少服务器内存使用却也没有大量减少,也可能是为什么有些时候重启下服务器情况就会好很多,因为重启后,php-fpm的子进程数会变成最小闲置进程数,而不是之前的最大闲置进程数。

max_requests

即是说每个进程若超过这个数目(跟php进程有一点点关系,关 系不大),就自动杀死.

max_children

最大进程数,一般来说一台服务器正常情况下每一个php-fpm所耗费的内存在40M左右,理想最大进程数可计算为1000/40=25,但是实际上内存不止有php-fpm在占用,故可根据实际情况来,适当减小使得内存不会因php-fpm进程过多而耗尽。而如果我 的”max_children”设置的较小,比如5-10个,那么php-fpm就会“很累”,处理速度也很慢,等待的时间也较长。如果长时间没有得到处 理的请求就会出现504 Gateway Time-out这个错误。

request_terminate_timeout

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

pm.start_servers

动态方式下的起始php-fpm进程数量

pm.min_spare_servers

动态方式下的最小php-fpm闲置进程数

pm.min_spare_servers

动态方式下的最大php-fpm闲置进程数量

三、相关命令参考

php-fpm 重启

kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

查看php-fpm进程数量

ps aux | grep -c php-fpm

查看内存占用情况

free

倒序查看内存详细占用情况

top ————> M

参考:

http://blog.csdn.net/pzqingchong/article/details/53379772

php-fpm优化方法 pm.min_spare_servers、pm.max_spare_servers

php-fpm进程池开启进程有两种方式,一种是static,直接开启指定数量的php-fpm进程,不再增加或者减少;
另一种则是dynamic,开始时开启一定数量的php-fpm进程,当请求量变大时,动态的增加php-fpm进程数到上限,

当空闲时自动释放空闲的进程数到一个下限。这两种不同的执行方式,可以根据服务器的实际需求来进行调整。

要用到的一些参数,分别是pm、pm.max_children、pm.start_servers、pm.min_spare_servers和pm.max_spare_servers。

pm表示使用那种方式,有两个值可以选择,就是static(静态)或者dynamic(动态)。

下面4个参数的意思分别为:

  • pm.max_children:静态方式下开启的php-fpm进程数量,在动态方式下他限定php-fpm的最大进程数(这里要注意pm.max_spare_servers的值只能小于等于pm.max_children)
  • pm.start_servers:动态方式下的起始php-fpm进程数量。
  • pm.min_spare_servers:动态方式空闲状态下的最小php-fpm进程数量。
  • pm.max_spare_servers:动态方式空闲状态下的最大php-fpm进程数量。如果dm设置为static,那么其实只有pm.max_children这个参数生效。系统会开启参数设置数量的php-fpm进程。php-fpm一个进程大概会占20m-40m的内存,所以他的数字大小的设置要根据你的物理内存的大小来设置,还要注意到其他的内存占用,如数据库,系统进程等,来确定以上4个参数的设定值!

如果dm设置为dynamic,4个参数都生效。系统会在php-fpm运行开始时启动pm.start_servers个php-fpm进程,

然后根据系统的需求动态在pm.min_spare_servers和pm.max_spare_servers之间调整php-fpm进程数。

参数要求pm.start_servers的值在pm.min_spare_servers和pm.max_spare_servers之间。

例:主机内存为1.6G,默认lnmp设置为20,10,10,20;改为如下25,5,5,25

因为网站访客人数很少,所以初始php-fpm线程5个就好了,不会占用过多内存,当访客突然增加,也会动态调整直到最高的限值25.

[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 = dynamic
pm.max_children = 25
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 25
request_terminate_timeout = 100
request_slowlog_timeout = 0
slowlog = var/log/slow.log

实时查看php-fpm的状态

在nginx里面加一个location就可以了,具体设置如下:

location ~ ^/status$ {
                include fastcgi_params;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
        }

然后在php-fpm.conf里面打开选项

pm.status_path = /status

这样的话通过http://域名/status就可以看到当前的php情况,以前之知道可以配置location来看nginx的状态,没想到还可以看php-fpm的状态,,真的是学习了,,看到的状态如下:

pool: www php运行的组
process manager: dynamic php-fpm运行的方式
start time: 04/Jun/2012:16:05:32 +0800 开始时间
start since: 5932
accepted conn: 65678 接受链接
listen queue: 0 监听队列
max listen queue: 1 最大监听队列
listen queue len: 128 监听队列len
idle processes: 82 空闲进程
active processes: 4 活动进程
total processes: 86 总进程
max active processes: 25 最大活动进程
max children reached: 0 最大的子进程达到

有了这个,就可以实时的查看php-fpm的状态,进而优化php-fpm

PHP-FPM进程CPU 飙高的原因及解决方案

在最近开发中,发现打开网页越来越慢,所以用用top命令发现,php-fpm CPU 飙到了90%以上,所以需要紧急处理这个问题,

未分类

主要解决思路如下:

1. 设置控制php-fpm进程池进程数量。

修改pm.max_children的数量,根据内存来进行分配,系统开一个进程20-30M。比如系统内存1G,那就将差不多能开30个进程,所以可以设置pm.max_children 为30,以此类推,然后需要重启下php-fpm服务。

pm.max_children:静态方式下开启的php-fpm进程数量。
pm.start_servers:动态方式下的起始php-fpm进程数量。
pm.min_spare_servers:动态方式下的最小php-fpm进程数量。
pm.max_spare_servers:动态方式下的最大php-fpm进程数量。

2. 开启慢日志。

编辑php-fpm.conf文件找到request_slowlog_timeout = 0这一行,默认值为0,表示不开启slowlog,将其值改为3s,表示跟踪执行时间达到或超过3s的脚本。找到slowlog,它的值表示慢执行日志的路径。

3.内存分配。

内存分配太少,理论上开一个进程消耗CPU 20-30M,所以1G内存的可以开30个进程左右,如果是虚拟机的话可以分配2G内存。

4. 编辑php-fpm.conf配置文件。

php_admin_value[memory_limit] = 128M(我服务器上的配置文件在/etc/php5/fpm/pool.d/www.conf 这个文件是被包含在php-fpm.conf里的) 后边的数字可以随便更改:32M,64M,128M,256M,512M,这个设置可根据你的服务器内存大小和你的需求来写,修改后要加载一下php-fpm服务。

欢迎补充!

Php-fpm的配置和优化

Nginx本身不能处理 php请求,它是一个web服务器,接收到php请求后,发给php解释器处理,并把结果返回给客户端

nginx 一般是把请求发给fastcgi 管理进程处理,fascgi管理进程选择cgi 子进程处理结果,并返回给nginx

未分类

php-fpm.conf 配置文件

[www]

pm.max_children = 15 #最大子进程数 

pm.start_servers = 2 #启动时创建的子进程数  

pm.max_requests = 500 #每个子进程可以处理的请求数 

slowlog = log/$pool.log.slow #慢日志 

request_slowlog_timeout = 10s #慢日志记录时间,注意单位,超时的会被纪录到slowlog的path文件中

rlimit_core = 1024

listen = /run/php/php7.2-fpm.sock 

;listen.allowed_clients = 127.0.0.1 #限制访问ip为localhost any为所有主机 

listen.owner = www-data #启动进程的用户

listen.group = www-data #启动进程的用户组

#以上两个配置需要和Server 相同

pm.max_requests = 500 #设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 '0' 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.

;request_terminate_timeout = 0 #设置单个请求的超时时间,这个设置和 php.ini 中配置的max_execution_time 这个参数一样,当max_execution_time 失效时,request_terminate_timeout 会被使用。


[global]
8
pid = /run/php/php7.2-fpm.pid 

error_log = /var/log/php7.2-fpm.log #错误日志path

log_level = warning #默认为notice 

daemonize = yes #后台执行fpm,默认值为yes