common gateway interface (公共网关接口)
Server 与 CGI 通过 STDIN/STDOUT(标准的输入/输出)进行数据传递 nginx(动态加载模块) apache(指定加载模块)
当然,这样在访问量很少没有并发的情况也行。可是当访问量增大,并发存在,这种方式就不 适合了。于是就有了fastcgi。
像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后, 不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。
php-fpm是 FastCGI 的实现,并提供了进程管理的功能,即php-Fastcgi Process Manager。 进程包含 master 进程和 worker 进程两种进程。
master 进程只有一个,负责监听端口,接收来自 Web Server 的请求, worker 进程则一般有多个(具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方。
大致原理如图:
该模式比较简单,在启动时按照配置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模式,运行流程和第一步相同,不同之处是在第二个函数中不会分配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); ...... }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_ACCEPTING if (fpm_request_is_idle(child)) { return; // FPM_REQUEST_ACCEPTING代表处于等待请求阶段 } } ...... fpm_children_make(wp, 1, 1, 1);//创建work进程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模式,启动时分配固定数量的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的倍数进行增长 } ...... }三种运行方式各有自己的优势,用哪种方式更合适,要根据自己的业务场景,选择合适的运行方式
参考:https://zhuanlan.zhihu.com/p/96911584 参考:https://blog.csdn.net/njrclj/article/details/85062459