PHP-FPM及其三种运行方式

  • php-fpm和FastCGI是什么?
    • fpm的基本实现
    • worker工作流程
    • fpm启动流程部分源码
  • php-fpm运行的三种模式
    • `static`模式:静态模式
    • `ondemand` 模式:按需分配模式
    • `dynamic`模式:动态模式
  • 总结

php-fpm和FastCGI是什么?

  1. PHP-FPM(FastCGI Process Manager)是一个PHPFastCGI进程管理器,从其英文名称和定义可以看出,FPM的核心功能就是进程管理。

  2. FastCGI可以理解为一种协议,用于web服务器(nginx、Apache)和处理程序间进行通信,是一种应用层通信协议。

  3. 工作原理大致如下图

fpm的基本实现

  1. 简单来说,fpm的实现就是创建一个master进程,在master进程中创建worker pool并监听socket,然后fork出多个子进程(work),这些worker在启动后阻塞在fcgi_accept_request()上,各自accept请求,有请求到达后worker开始读取请求数据,读取完成后开始处理然后再返回,在这期间是不会接收其它请求的,也就是说fpm的子进程同时只能响应一个请求,只有把这个请求处理完成后才会accept下一个请求。
  2. fpm的master进程与worker进程之间不会直接进行通信,master通过共享内存获取worker进程的信息,比如worker进程当前状态、已处理请求数等,当master进程要杀掉一个worker进程时则通过发送信号的方式通知worker进程。
  3. fpm可以同时监听多个端口,每个端口对应一个worker pool,而每个pool下对应多个worker进程,类似nginx中server概念, 在php-fpm.conf中可以配置多个,例如:
    [web1]
    listen:127.0.0.1:9000
    [web2]
    listen:127.0.0.1:9001
  4. 大致原理如下图
  5. php-fpm源码结构
struct fpm_worker_pool_s {struct fpm_worker_pool_s *next; //指向下一个worker poolstruct fpm_worker_pool_config_s *config; //conf配置:pm、max_children、start_servers......struct fpm_child_s *children; //当前pool的worker链表int running_children; //已启动的进程数int idle_spawn_rate;//空闲率int warn_max_children;//最大work值struct fpm_scoreboard_s *scoreboard; //记录worker的运行信息,比如空闲、忙碌worker数...
}

以上代码片段只保留了部分本文所需要的内容

worker工作流程

worker的工作流程包含以下几个步骤

  1. 等待请求:fcgi_accept_request()阻塞等待请求
  2. 接收请求:fastcgi请求到达后被worker接收并解析,一直到完全接收,然后将method、query、uri等信息保存到worker进程的fpm_scoreboard_proc_s结构中
  3. 初始化请求:php_request_startup()执行,此步骤会调用每个扩展的PHP_RINIT_FUNCTION方法,初始化一些操作
  4. 处理请求(编译、执行):php代码编译执行阶段,由 php_execute_script方法完成
  5. 关闭请求:返回响应,执行php_request_shutdown方法关闭请求,然后进入第一步继续等待请求,此步骤会执行每个扩展的PHP_RSHUTDOWN_FUNCTION进行一些收尾工作

fpm启动流程部分源码

int main(int argc, char *argv[])
{...变量定义,参数初始化//注册SAPIsapi_startup(&cgi_sapi_module);...//执行php_module_starup()if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {return FPM_EXIT_SOFTWARE;}//初始化if(0 > fpm_init(...)){//记录日志并退出return FPM_EXIT_CONFIG;}...fpm_is_running = 1;//fpm运行状态标识fcgi_fd = fpm_run(&max_requests);//进程初始化,调用fork()创建work进程...fcgi_init_request(&request, fcgi_fd); //初始化请求;//此阶段的php_request_startup()会调用每个扩展的:PHP_RINIT_FUNCTION();if (UNEXPECTED(php_request_startup() == FAILURE)) {...}...php_fopen_primary_script(&file_handle TSRMLS_CC); //打开脚本; ...php_execute_script(&file_handle TSRMLS_CC); //执行脚本; ...//worker进程退出php_module_shutdown();...
}

以上代码片段只保留了部分本文所需要的内容

php-fpm运行的三种模式

static模式:静态模式

该模式比较简单,在启动时按照配置pm.max_children启动固定数量的的进程,这些进程阻塞进行请求的接收
方法执行流程:
fpm_run()->fpm_children_create_initial()->fpm_children_make()
启动fpm的时候会调用fpm_run方法,而fpm_run方法内部会调用子进程初始化方法fpm_children_create_initial
在该方法内部会调用fpm_children_make方法创建worker进程。

ondemand 模式:按需分配模式

  1. ondemand模式,运行流程和第一步相同,不同之处是在第二个函数中不会分配work进程,而是注册了一个事件回调函数fpm_pctl_on_socket_accept(),部分代码如下:
if (wp->config->pm == PM_STYLE_ONDEMAND) { wp->ondemand_event = (struct fpm_event_s *)malloc(sizeof(struct fpm_event_s));   ......   memset(wp->ondemand_event, 0, sizeof(struct fpm_event_s));    fpm_event_set(wp->ondemand_event,wp->listening_socket,FPM_EV_READ|FPM_EV_EDGE,fpm_pctl_on_socket_accept, wp);    ......
}

以上代码片段只保留了部分本文所需要的内容

  1. ondemand模式work进程的创建,回调函数fpm_pctl_on_socket_accept()的部分代码如下:
if (wp->running_children >= wp->config->pm_max_children) {   //判断进程数是否超过最大限制......    return;
}
for (child = wp->children; child; child = child->next) { //fpm_request_is_idle函数返回return proc->request_stage == FPM_REQUEST_ACCEPTINGif (fpm_request_is_idle(child)) { return;   // FPM_REQUEST_ACCEPTING代表处于等待请求阶段}
}
......
fpm_children_make(wp, 1, 1, 1);//创建work进程

以上代码片段只保留了部分本文所需要的内容

  1. ondemand模式work进程的关闭
    PFM注册了一个定时事件fpm_pctl_perform_idle_server_maintenance_heartbeat检查当前模式下work进程的运行情况,当空闲进程等待请求时间超过pm_process_idle_timeout后,会对最后一个空闲worker进程发出关闭信号,此操作由主进程进行处理,部分代码如下:
if (wp->config->pm == PM_STYLE_ONDEMAND) {struct timeval last, now;    if (!last_idle_child) continue;//最后一个idle进程......// last.tv_sec为上次接收请求的时间if (last.tv_sec < now.tv_sec - wp->config->pm_process_idle_timeout) {last_idle_child->idle_kill = 1;fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_QUIT);}continue;
}

以上代码片段只保留了部分本文所需要的内容

dynamic模式:动态模式

dynamic模式,启动时分配固定数量的work进程,然后随着请求的增加会增加进程数,此模式下几个重要的配置项如下:
max_children 最大进程数
pm_max_spare_servers 允许最大的空闲进程数
min_spare_servers 允许最小的空闲进程数
start_servers 启动时的进程数
执行过程和ondemand模式类似,启动时主进程都会创建一个定时事件来定时检查work的运行状况,不同的是dynamic模式初始化的时候会创建一定数量的进程,而ondemand模式不会创建,部分代码如下:

if (idle > wp->config->pm_max_spare_servers && last_idle_child) {//空闲进程数大于配置的允许空闲最大进程数,则关闭进程last_idle_child->idle_kill = 1;fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_QUIT);......
}
if (idle < wp->config->pm_min_spare_servers) {//空闲进程数小于配置允许的最小进程数,则创建进程if (wp->running_children >= wp->config->pm_max_children) {//如果达到最大上限,则不再创建......continue;}......
//此处计算出需要扩充的进程数,从wp->idle_spawn_rate, wp->config->pm_min_spare_servers – idle, wp->config->pm_max_children - wp->running_children三个中选出最小的一个作为本次要扩充的进程数进行扩充
if (wp->idle_spawn_rate >= 8) {zlog(ZLOG_WARNING, "[pool %s] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning %d children, there are %d idle, and %d total children", wp->config->name, wp->idle_spawn_rate, idle, wp->running_children);}if (wp->idle_spawn_rate < FPM_MAX_SPAWN_RATE) {wp->idle_spawn_rate *= 2;//当前进程分配基数小于配置值时候,会以2的倍数进行增长}......
}

总结

以上就是本人对php-fpm以及php-fpm的三种运行方式的理解,三种运行方式中,
static模式最简单,但是灵活性不够高
ondemand模式相对static模式比较复杂,会根据请求量的增加动态增加,但是处理完请求后不会立即释放,而是由定时事件定时的检测空闲到一定时间的进程才会释放
dynamic模式类似于ondemand模式,但进程的回收机制不同于ondemand模式,会根据idle数量进行增加和减少worker数量

三种运行方式各有自己的优势,用哪种方式更合适,要根据自己的业务场景,选择合适的运行方式

PHP-FPM及其三种运行方式相关推荐

  1. Windows下图文详解PHP三种运行方式(php_mod、cgi、fastcgi)

    PHP能不能成功的在Apache服务器上运行,就看我们如何去配置PHP的运行方式.PHP运行目前为止主要有三种方式: a.以模块加载的方式运行,初学者可能不容易理解,其实就是将PHP集成到Apache ...

  2. python的编程模式有哪两种_python程序的两种运行方式是什么

    python程序的两种运行方式是什么 第一种方式:REPL 所谓REPL即read.eva.print.loop(读取.计算.打印.循环),实现REPL运行方式有以下两种: 1.IDLE( 集成开发环 ...

  3. python idle 常规命令_Python的3种运行方式:命令行窗口、Python解释器、IDLE的实现

    1 命令行窗口 开始栏搜索command,打开命令提示符,即为命令行窗口. 运行一个Python程序,需要输入:Python + 程序地址 + 程序名.py 如图: 2 Python解释器 开始栏搜索 ...

  4. python的运行方式有哪两种 有何区别_python程序的两种运行方式是什么

    python程序的两种运行方式是什么 第一种方式:REPL 所谓REPL即read.eva.print.loop(读取.计算.打印.循环),实现REPL运行方式有以下两种: 1.IDLE( 集成开发环 ...

  5. springboot项目有哪几种运行方式

    springboot项目有哪几种运行方式 打包用命令或者放到容器中运行 用 Maven/Gradle 插件运行 直接执行 main 方法运行

  6. php 的几种运行方式

    php 的几种运行方式 CGI FAST-CGI Web-module CLI CGI CGI (Common Gateway Interface) 是通用网关型接口,CGI是外部应用程序(CGI程序 ...

  7. python-字典及其三种定义方法

    字典及其三种定义方法 文章目录 字典及其三种定义方法 字典 使用不可变数值充当key key如果重复的话,只会显示最后一个键值对 定义字典的三种方式 -直接定义 定义字典的三种方式 -使用dict函数 ...

  8. 听六小桨讲AI | 第3期:优化器及其三种形式BGD、SGD以及MBGD

    点击左上方蓝字关注我们 本栏目由百度飞桨工程师联手精心打造,对深度学习的知识点进行由浅入深的剖析和讲解.大家可视它为深度学习百科(面试秘籍也是可以哒),当然也可收藏为深度学习查询手册~ 大家好,我是助 ...

  9. java的两种运行方式Applet和Application你真的懂吗

    对两者的简介 他们是java的两种程序,能够独立运行的程序称为Java应用程序也包含我们正常写的java文件所生成的可执行程序(Application)其运行和普通的java文件相同.Java语言还有 ...

最新文章

  1. 李开复:发明期已过,AI科学家创业需谨慎(附演讲视频)
  2. 从91移动应用发展趋势报告看国内应用现状
  3. HDU-6290_奢侈的旅行(Dijstra+堆优化)
  4. 160家优秀国外技术公司博客
  5. Ubuntu没有/etc/apt/sources.list文件的解决办法
  6. Python基础38(进程基础)
  7. Python爬取js动态添加的内容
  8. MySQL二进制日志文件的用法_数据恢复
  9. jquerymobile使用技巧
  10. C++基础知识友元friend、友元函数和友元类
  11. 动态规划应用--最长递增子序列 LeetCode 300
  12. checked jq 添加_jquery动态添加复选框.attr(“checked”,true)不起作用
  13. ble l2cap 工作过程_BLE 链路层报文详解
  14. MySql中的count函数
  15. 拖放drag drop(PyQt或Qt for python)
  16. 无法创建java虚拟机_创建java虚拟机失败的解决方法
  17. QQ的DLL文件修改大全!
  18. 一阶微分方程的物理意义_如何从物理意义上理解NS方程?
  19. GGGIS地图下载器
  20. Windows常用cmd命令总结

热门文章

  1. thymeleaf中th:attr
  2. 培养批判性思维的起点:从小学习区分Facts(事实) amp; Opinions(观点)
  3. 2008~2014,这6年我都学了啥干了啥
  4. CocoaPods安装指定版本
  5. 在Excel中四舍五入的7种方法
  6. Spring Boot微服务间文件返回实现
  7. 管理理念:非金钱激励员工的108种手段
  8. 八大激励模式让员工更具活力
  9. MYSQL(分组函数,分组查询)
  10. 对于多功能智能眼镜你有什么设想和创意。和思路