深入理解PHP-FPM

FPM是什么


FPM(FastCGI Process Manager)是PHP FASTCGI运行模式的一个进程管理器。

问题来了,既然是进程管理器,用来管理什么进程呢?
这就引出FastCGI协议

什么是FastCGI协议?
FastCGI是web服务器(如Nginx、Apache)和处理程序之间的一种通信协议。它是与HTTP类似的一种应用层通信协议。注意:它只是一种协议。
在网络应用场景下,PHP并没有像GOlang那样实现HTTP网络库,而是实现的FastCGI协议,然后与web服务器配合实现了HTTP的处理,web服务器来处理HTTP请求,然后将解析的结果再通过FastCGI协议转发给处理程序,处理程序处理完成后将结果返回给web服务器,web服务器再返回给用户。

扩展之-常用的网络处理模型

  • 多进程模型:由一个主进程和多个子进程组成,主进程负责管理子进程,基本的网络事件由多个子进程处理,Nginx采用的就是这种模型。
  • 多线程模型:与多进程类型,只是它是线程粒度,这种模型通常会由主进程监听、接收请求,然后交由子线程处理,memcached就是这种模式;有的也是采用多进程那种模式-主线程只负责管理子线程不处理网络事件,各个子线程监听、接收、处理请求,memcached使用UDP协议时采用的是这种模式。

进程拥有独立的地址空间及资源,而线程没有,线程之间共享进程的地址空间及资源,所以在资源管理上多进程模型比较简单,而多线程模型则需要考虑不同线程之间资源冲突,也就是线程安全。

基本实现


FPM是一个多进程模型,它由一个master进程和多个worker进程组成。master进程启动时会创建一个socket,但是不会接收、处理请求,而是fork出多个worker子进程完请求的接收及处理。

master进程的主要工作是管理worker进程,负责fork或者kill掉进程,比如当请求比较多处理不过来时,master进程会尝试fork新的worker进程进程处理,而当空闲worker进程比较多时则会杀掉部分子进程,避免占用、浪费系统资源。

worker进程的主要工作是处理请求,每个worker进程会竞争的Accept请求,接受成功后解析FastCGI,然后执行相应的脚本,处理完成后关闭请求,继续等待新的连接,这就是一个worker进程的生命周期。从worker进程的生命周期可以看到:一个worker进程只能处理一个请求,只有将一个请求处理完成后才会处理下一个请求。这与Nginx的事件模型有很大的区别,Nginx的子进程通过epoll管理套接字,如果一个请求数据还未发送完成则会处理下一个请求,它是非阻塞的模型,只处理活跃的套接字。FPM的这种处理模式大大简化了PHP的资源管理,使得在FPM模式下不需要考虑并发导致的资源冲突。

master进程与worker进程之间不会直接进行通信,master通信共享内存获取worker进程的信息,比如worker进程当前状态、已处理请求数等,master进程通过发送信号的方式杀掉worker进程。

FPM可以同时监听多个端口,每个端口对应一个worker pool,每个pool下对应多个worker进程,类似Nginx中server的概念,这些归属不同pool的worker进程扔由一个master管理。worker pool的结构为fpm_worker_pool_s,pool之间构成一个链表
在php-fpm.conf中通过[pool name]声明一个worker pool,每个pool各自配置监听的地址、进程管理方式、worker进程数等。

[pool name1]
listen = 127.0.0.1:9000
...
[pool name2]
listen = 127.0.0.1:9001
...
;isten = /dev/shm/php-fpm0.socket //可以使用tcp或者unix socket的方式,但是必须区别于其他池的配置,比如tcp的端口不能一样,socket的文件不能一样
pm=dynamic   //进程模型: static、dynamic、ondemand
pm.max_children=50 //最大worker进程数
pm.start_servers=5 //启动时初始化的worker数
pm.min_spare_servers=5 //最小空闲worker数
pm.max_spare_servers=35  //最大空闲worker数
pm.process_idle_timeout=10  //worker空闲时间
pm.pm_max_requests //worker处理的最多请求数,超过这个值worker将被kill

扩展之PHP-FPM的多个进程池

每个池使用不同的配置,各个池之间互不干涉。默认情况下,PHP 只启用了一个池,所有请求均在这个池中执行。一旦某些请求出现拥堵之类的情况,那么很可能会连累整个池出现问题;如果启用多个池,那么可以把请求分门别类放到不同的池中执行,此时如果某些请求出现拥堵之类的情况,那么只会影响自己所在的池,从而控制故障的波及范围。

设置多个进程池,每个进程池分配不同的站点,可以做到一个站占用资源过多导致其它站也不能访问的尴尬情况。这使得网站可以更好的运行,如果某个站点受到少量CC攻击,也不至于拖跨所有的站点。

参考书籍:《PHP7内核剖析》

你可能感兴趣的:(php-fpm,php7)