[TOC]
:-: ![PHP-FPM](https://img.kancloud.cn/c0/71/c071301f232b8f9623faee4b3e9284ac_724x304.png)
## 简介
**PHP-FPM**(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。
它的功能包括:
* 支持平滑停止/启动的高级进程管理功能;
* 可以工作于不同的 uid/gid/chroot 环境下,并监听不同的端口和使用不同的 php.ini 配置文件(可取代 `safe_mode` 的设置);
* stdout 和 stderr 日志记录;
* 在发生意外情况的时候能够重新启动并缓存被破坏的 opcode;
* 文件上传优化支持;
* "慢日志" - 记录脚本(不仅记录文件名,还记录 PHP backtrace 信息,可以使用 ptrace或者类似工具读取和分析远程进程的运行数据)运行所导致的异常缓慢;
* `fastcgi_finish_request()` - 特殊功能:用于在请求完成和刷新数据后,继续在后台执行耗时的工作(录入视频转换、统计处理等);
* 动态/静态子进程产生;
* 基本 SAPI 运行状态信息(类似 Apache 的 mod_status);
* 基于 php.ini 的配置文件。
## 工作原理
php-fpm启动 -> 生成 n 个 fast-cgi 协议处理进程 -> 监听一个端口等待任务
用户请求 -> web 服务器接收请求 -> 请求转发给 php-fpm -> php-fpm 交给一个空闲进程处理 -> 进程处理完成 -> php-fpm 返回给 web 服务器 -> web服务器接收数据 -> 返回给用户
## 工作模式
php-fpm 进程管理一共有三种模式:ondemand、static、dynamic。
php-fpm 的工作模式和 nginx 类似,都是一个 master,多个 worker 模型。每个 worker 都在 accept 本 pool 内的监听套接字。
### 静态模式 **static**
php-fpm 启动时采用固定大小数量的worker,在运行期间也不会扩容,虽然也有1秒的定时器,仅限于统计一些状态信息,例如空闲worker个数,活动worker个数,网络连接队列长度等信息。
php-fpm.conf:
~~~text
[test]
listen = 127.0.01:9000
pm = static
pm.max_children = 40 # 大于0 ,必须配置,且只有这一个参数生效
~~~
### 动态模式 **dynamic**
在 php-fpm 启动时,会初始启动一些 worker,在运行过程中动态调整 worke 数量,worke r的数量受限于pm.max_children 配置,同时受限全局配置 process.max 。
~~~text
[test]
listen = 127.0.01:9000
pm = dynamic
pm.max_children = 10 # 大于 0
pm.start_servers = 2 # 有效范围 [pm.min_spare_servers, pm.max_spare_servers] 如果没有配置,默认pm.min_spare_servers + (pm.max_spare_servers - pm.min_spare_servers) / 2
pm.min_spare_servers = 1 # <= pm.max_spare_servers
pm.max_spare_servers = 6
~~~
#### 原理
初始启动 `pm.min_spare_servers` 个 worker,而最大子进程数则由 `pm.max_children` 去控制,闲置的子进程数则由`pm.min_spare_servers`和`pm.max_spare_servers`控制,如果闲置的子进程超出了`pm.max_spare_servers`,则会被杀掉。master 进程中设置了 1秒定时器,检查空闲 worker 数量,按照一定策略动态调整 worker 数量,增加或减少。
#### 优缺点
- 优点:动态扩容,不浪费系统资源,master进程设置的1秒定时器对系统的影响忽略不计;
- 缺点:如果所有worker都在工作,新的请求到来只能等待master在1秒定时器内再新建一个worker,这时可能最长等待1s;
### 按需分配 **ondemand**
在 php-fpm 启动的时候,不会给这个 pool 启动任何一个 worker,是按需启动,当有连接过来才会启动。
~~~text
[test]
listen = 127.0.01:9000
pm = ondemand
pm.process_idle_timeout = 60 # 大于0,如果不设置,默认10s
pm.max_children = 10 # 大于0
~~~
#### 原理
新建 worker 的触发条件是连接的到来,而不是实际的请求(只进行连接比如 telnet,不发请求数据也会新建 worker)
worker 的数量受限于 `pm.max_children` 配置,同时受限全局配置 `process.max`
master 进程中 1秒定时器会找到空闲 worker ,如果空闲时间超所 `pm.process_idle_timeout` ,则关闭,这个机制可能会关闭所有的 worker。
#### 优缺点
- 优点:按流量需求创建,不浪费系统资源(在硬件如此便宜的时代,这个优点略显鸡肋)
- 缺点:由于 php-fpm 是短连接的,所以每次请求都会先建立连接,所以,在大流量的系统上 master 进程会变得繁忙,占用系统 cpu 资源,不适合大流量环境的部署
## PHP-fpm 与 Nginx 的通信方式
### **unix socket**
* nginx 方面需要指定`fastcgi_pass unix:/xxx/xxx/xxx.sock`,如:
~~~text
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;;
fastcgi_pass unix:/var/run/php7-fpm.sock;
fastcgi_index index.php;
}
~~~
* 相应地,php-fpm 方面需要指定`listen = /xxx/xxx/xxx.sock`,如:
~~~text
listen = /var/run/php-fpm.sock
~~~
### **tcp socket**
* nginx 方面需要指定`fastcgi_pass ip:port`,如:
~~~text
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}
~~~
* 相应地,php-fpm 方面需要指定`listen = ip:port`,如:
~~~json
listen = 127.0.0.1:9000
~~~
带有权重的集群:
~~~json
upstream api_fpm {
server ip1:port1 weight=x1;
server ip2:port2 weight=x2;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;;
fastcgi_pass api_fpm;
fastcgi_index index.php;
}
~~~
### 对比
* `unix socket`基于本地`.sock`文件通信,省去底层网络协议传输的消耗,更高效。
* `tcp socket`配合`nginx 的 upstream`实现了集群部署,更利于水平扩展。
* 基于上述特点:
* 不需要集群,追求快速影响时,选择`unix socket`。
* 更注重服务稳定性和可扩展性时,选择`tcp socket`。
- PHP
- PHP 核心架构
- PHP 生命周期
- PHP-FPM 详解
- PHP-FPM 配置优化
- PHP 命名空间和自动加载
- PHP 运行模式
- PHP 的 Buffer(缓冲区)
- php.ini 配置文件参数优化
- 常见面试题
- 常用函数
- 几种排序算法
- PHP - 框架
- Laravel
- Laravel 生命周期
- ThinkPHP
- MySQL
- 常见问题
- MySQL 索引
- 事务
- 锁机制
- Explain 使用分析
- MySQL 高性能优化规范
- UNION 与 UNION ALL
- MySQL报错:sql_mode=only_full_group_by
- MySQL 默认的 sql_mode 详解
- 正则表达式
- Redis
- Redis 知识
- 持久化
- 主从复制、哨兵、集群
- Redis 缓存击穿、穿透、雪崩
- Redis 分布式锁
- RedisBloom
- 网络
- 计算机网络模型
- TCP
- UDP
- HTTP
- HTTPS
- WebSocket
- 常见几种网络攻击方式
- Nginx
- 状态码
- 配置文件
- Nginx 代理+负载均衡
- Nginx 缓存
- Nginx 优化
- Nginx 配置 SSL 证书
- Linux
- 常用命令
- Vim 常用操作命令
- Supervisor 进程管理
- CentOS与Ubuntu系统区别
- Java
- 消息队列
- 运维
- RAID 磁盘阵列
- 逻辑分区管理 LVM
- 业务
- 标准通信接口设计
- 业务逻辑开发套路的三板斧
- 微信小程序登录流程
- 7种Web实时消息推送方案
- 用户签到
- 用户注册-短信验证码
- SQLServer 删除同一天用户重复签到
- 软件研发完整流程
- 前端
- Redux
- 其他
- 百度云盘大文件下载
- 日常报错记录
- GIT
- SSL certificate problem: unable to get local issuer certificate
- NPM
- reason: connect ECONNREFUSED 127.0.0.1:31181
- SVN
- SVN客户端无法连接SVN服务器,主机积极拒绝
- Python
- 基础
- pyecharts图表
- 对象
- 数据库
- PySpark
- 多线程
- 正则
- Hadoop
- 概述
- HDFS