## php\-fpm是什么?
PHP5.3.3开始集成了php-fpm模块,不再是第三方的包了。PHP\-FPM提供了更好的PHP[进程管理](https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86)方式,可以有效控制内存和进程、可以平滑\[重载\](https://baike.baidu.com/item/%E9%87%8D%E8%BD%BD)PHP配置。
重点:
> php-fpm是fastcgi的实现。
## php-fpm的运行模型?
> 多进程同步阻塞模式
php-fpm是一种master(主)/worker(子)多进程架构模型。
当PHP-FPM启动时,会读取配置文件,然后创建一个Master进程和若干个Worker进程(具体是几个Worker进程是由php-fpm.conf中配置的个数决定)。Worker进程是由Master进程fork出来的。
**master进程主要负责CGI及PHP环境初始化、事件监听、Worker进程状态等等,worker进程负责处理php请求**。
master进程负责创建和管理woker进程,同时负责监听listen连接,**master进程是多路复用的**;woker进程负责accept请求连接,同时处理请求,**一个woker进程可以处理多个请求**(**复用**,不需要每次都创建销毁woker进程,而是达到处理一定请求数后销毁重新fork创建worker进程),**但一个woker进程一次只能处理一个请求**。
https://img.kancloud.cn/41/ed/41ed99b258dd1703acd803c8de18db1f_640x226.png
## cgi,php-cgi,php-fpm,fastcgi的区别?
**cgi**
cgi是一个web server与cgi程序(这里可以理解为是php解释器)之间进行数据传输的协议,保证了传递的是标准数据。(服务端和解释器之间的数据传输协议)
***php-cgi**
php-cgi是php解释器。他自己本身只能解析请求,返回结果,不会管理进程。php-fpm是调度管理php-cgi进程的程序。(php解释器,由php-fpm调度)
***Fastcgi**
Fastcgi是用来提高cgi程序(php\-cgi)性能的方案/协议。
cgi程序的性能问题在哪呢?"PHP解析器会解析php.ini文件,初始化执行环境",就是这里了。**标准的CGI对每个请求都会执行这些步骤,所以处理的时间会比较长**。
Fastcgi会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复劳动,效率自然提高。而且当worker不够用时,master可以根据配置预先启动几个worker等着;当然空闲worker太多时,也会停掉一些,这样就提高了性能,也节约了资源。这就是Fastcgi的对进程的管理。
\* \*\*php-fpm\*\*
\*\*fastcgi是一个方案或者协议,php-fpm就是FastCGI的后端实现\*\*,也就是说,进程分配和管理是FPM来做的。官方对FPM的解释:【Fastcgi Process Manager】【Fastcgi 进程管理器】。
php\-fpm的管理对象是php\-cgi,他负责管理一个进程池,来处理来自Web服务器的请求。
对于php.ini文件的修改,php\-cgi进程是没办法平滑重启的,有了php\-fpm后,就把平滑重启成为了一种可能,php\-fpm对此的处理机制是新的worker用新的配置,已经存在的worker处理完手上的活就可以歇着了,通过这种机制来平滑过度的。
## php\-fpm如何完成平滑重启?
修改php.ini之后,php\-cgi进程的确是没办法平滑重启的。php\-fpm对此的处理机制是新的worker用新的配置,已经存在的worker处理完手上的活就可以歇着了,通过这种机制来平滑过度。
## php\-fpm和nginx的通信机制是怎么样的?
看下nginx的配置文件:
Nginx中fastcgi_pass的配置:
~~~
location ~ .php$ {
root /home/wwwroot;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
#fastcgi_pass unix:/tmp/php-cgi.sock;
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\\.php)(/.+)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
~~~
因为nginx不能直接执行php,所以需要借用fastcgi模块,和php\-fpm进行通信。有两种方式;
**1. TCP**
**2. UNIX Domain Socket**
TCP是IP加端口,可以跨服务器;
而UNIX Domain Socket不经过网络,只能用于Nginx跟PHP\-FPM都在同一服务器的场景。具体配置:
~~~
方式1:
php-fpm.conf: listen = 127.0.0.1:9000
nginx.conf: fastcgi_pass 127.0.0.1:9000;
方式2:
php-fpm.conf: listen = /tmp/php-fpm.sock
nginx.conf: fastcgi_pass unix:/tmp/php-fpm.sock;
~~~
值得一提的是,MySQ命令行客户端连接mysqld服务也类似有这两种方式:
使用Unix Socket连接(默认):
~~~
mysql -uroot -p --protocol=socket --socket=/tmp/mysql.sock
~~~
使用TCP连接:
~~~
mysql -uroot -p --protocol=tcp --host=127.0.0.1 --port=3306
~~~
## php-fpm在请求链路的体现,画出来?
~~~
www.example.com
|
|
\\!/
Nginx
|
|
\\!/
路由到www.example.com/index.php
|
|
\\!/
加载nginx的fast-cgi模块
|
|
\\!/
fast-cgi监听127.0.0.1:9000地址
|
|
\\!/
www.example.com/index.php请求到达127.0.0.1:9000
|
|
\\!/
php-fpm 监听127.0.0.1:9000
|
|
\\!/
php-fpm 接收到请求,启用worker进程处理请求
|
|
\\!/
php-fpm 处理完请求,返回给nginx
|
|
\\!/
nginx将结果通过http返回给浏览器
~~~
## php-fpm有几种工作模式?
PHP-FPM进程管理方式有动态(Dynamic)、静态(Static)、按需分配(Ondemand)三种。
**动态**
会初始化创建一部分worker,在运行过程中,动态调整worker数量,最大worker数受pm.max_children和process.max
~~~
listen = 127.0.0.1:9001
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 6
~~~
1. 当空闲进程数小于min_spare_servers时,创建新的子进程,总子进程数小于等于pm.max_children,小于等于process.max
2. 当空闲进程数大于max_spare_servers,会杀死启动时间最长的子进程
3. 如果子进程(idle状态)数大于max_children,会打印warning日志,结束处理
4. process小于 max_children ,计算一个num,启动num个worker
5. 优点:动态扩容,不浪费系统资源
6. 缺点:所有worker都在工作,新的请求到来需要等待创建worker进程,最长等待1s(内部存在一个1s的定时器,去查看,创建进程),频繁启停进程消耗cpu,请求数稳定,不需要频繁销毁
**静态**
启动固定大小数量的worker,也有1s的定时器,用于统计进程的一些状态信息,例如空闲worker个数,活动worker个数
~~~
pm.max_children = 10 #必须配置这个参数,而且只有这个参数有效
~~~
1. 优点:不用动态判断负载,提升性能
2. 缺点:如果配置成static,只需要考虑max_children数量,数量取决于cpu的个数和应用的响应时间,一次启动固定大小进程浪费系统资源
**按需分配**
php-fpm启动的时候不会启动worker进程,按需启动worker,有链接进来后,才会启动
~~~
listen = 127.0.0.1:9001
pm = ondemand
pm.process_idle_timeout = 60
pm.max_children = 10
~~~
连接到来时(只有链接,不没有数据也会创建,telnet也会创建),创建新worker进程,worker进程数的创建收max_children设置限制,也受限于全局的process.max设置(三种模式都受限此,下文中有全局配置项讲解),如果空闲时间超过了process_idle_timeout的设置就会销毁worker进程
* 优点:按流量需求创建,不浪费系统资源,
* 缺点:因为php-fpm是短连接的,如果每次请求都先建立连接,大流量场景下会使得master进程变得繁忙,浪费cpu,不适合大流量模式
* 不推荐使用此模式
| 工作模式 | 特点 |
| --- | --- |
| 动态 | 均衡优先,适合小内存服务器,2g左右 |
| 静态 | 性能优先, 适合大内存机器 |
| 按需分配 | 内存优先,适合微小的内存,2g以下 |
## 怎么选定php-fpm的worker进程数?
* 动态建立进程个数
* N+20% 到 M/m之间
* N是cpu核数,M是内存,m是每个php进程内存数
* 静态进程个数
* M/(m*1.2)
* pm.max_requests, 设置最大请求数,达到这个数量以后,会自动长期worker进程,繁殖内存意外增长
注意:PHP程序在执行完成后,或多或少会有内存泄露的问题。这也是为什么开始的时候一个php-fpm进程只占用3M左右内存,运行一段时间后就会上升到20-30M。所以需要每个worker进程处理完一定的请求后,销毁重新创建。
cpu密集型的pm.max_children不能超过cpu内核数,但是web服务属于IO密集型的,可以将pm.max_children的值设置大于cpu核数。
## php-fpm如何优化?
(1)避免程序跑死(hang)
在负载较高的服务器上定时重载php-fpm,reload可以平滑重启而不影响生产系统的php脚本运行,每15分钟reload一次,定时任务如下:
~~~
0-59/15 * * * * /usr/local/php/sbin/php-fpm reload
~~~
(2)合理增加单个worker进程最大处理请求数,减少内存消耗
最大处理请求数是指一个php-fpm的worker进程在处理多少个请求后就终止掉,master进程会重新respawn新的。该配置可以避免php解释器自身或程序引起的memory leaks。默认值是500,可以修改为如下配置:
~~~
pm.max_requests = 1024
~~~
(3)开启静态模式,指定数量的php-fpm进程,减少内存消耗
- 消息队列
- 为什么要用消息队列
- 各种消息队列产品的对比
- 消息队列的优缺点
- 如何保证消息队列的高可用
- 如何保证消息不丢失
- 如何保证消息不会重复消费?如何保证消息的幂等性?
- 如何保证消息消费的顺序性?
- 基于MQ的分布式事务实现
- Beanstalk
- PHP
- 函数
- 基础
- 基础函数题
- OOP思想及原则
- MVC生命周期
- PHP7.X新特性
- PHP8新特性
- PHP垃圾回收机制
- php-fpm相关
- 高级
- 设计模式
- 排序算法
- 正则
- OOP代码基础
- PHP运行原理
- zavl
- 网络协议new
- 一面
- TCP和UDP
- 常见状态码和代表的意义以及解决方式
- 网络分层和各层有啥协议
- TCP
- http
- 二面
- TCP2
- DNS
- Mysql
- 锁
- 索引
- 事务
- 高可用?高并发?集群?
- 其他
- 主从复制
- 主从复制数据延迟
- SQL的语⾔分类
- mysqlQuestions
- Redis
- redis-question
- redis为什么那么快
- redis的优缺点
- redis的数据类型和使用场景
- redis的数据持久化
- 过期策略和淘汰机制
- 缓存穿透、缓存击穿、缓存雪崩
- redis的事务
- redis的主从复制
- redis集群架构的理解
- redis的事件模型
- redis的数据类型、编码、数据结构
- Redis连接时的connect与pconnect的区别是什么?
- redis的分布式锁
- 缓存一致性问题
- redis变慢的原因
- 集群情况下,节点较少时数据分布不均匀怎么办?
- redis 和 memcached 的区别?
- 基本算法
- MysqlNew
- 索引new
- 事务new
- 锁new
- 日志new
- 主从复制new
- 树结构
- mysql其他问题
- 删除
- 主从配置
- 五种IO模型
- Kafka
- Nginx
- trait
- genergtor 生成器
- 如何实现手机扫码登录功能
- laravel框架的生命周期