nginx中php-fpm 和fastcgi什么关系

我们知道nginx.conf中配需要配置fastCGI,php需要安装php-fpm扩展并启动php-fpm守护进程,nginx才可以解析php脚本。

直接说问题吧:
1.在Nginx中,是不是一定要配置php-fpm才能解析PHP?
2.到底解析PHP的是php-fpm还是fastcgi还是其他的东西?
3.php-fpm,fastcgi,phpcgi关系是什么?
4.有人说fastcgi是一个接口协议,是把nginx和php进行解耦了。php-fpm是实现这个接口的工具。不知道这个理解是不是对的??

看了很多相关文章,感觉都不知道在说什么,没有人讲清楚的,希望各位自己的理解说说这些问题

阅读 5.3k
6 个回答
  1. 配置了php-fpm也不能解析php文件,nginx只是个转发,fastcgi_pass就像proxy_pass一样,转发
  2. 解析PHP的是php-fpm
  3. php-cgi实现CGI(通用网关接口,来新请求就需要fork新进程处理,效率低),php-fpm实现fastcgi(进程一直存活)
  4. fastcgi是协议,php-fpm根据该协议数据进程请求处理与响应,nginx根据该协议发出请求到php-fpm以及收取php-fpm返回的数据

那好,就说说我的理解:

  1. Nginx本身无法解析php,所以它需要一个执行环境(runtime)来解析它,这个运行时环境是zend,php-fpm负责接受nginx的请求并传递给zend。
  2. fastcgi不管解析的事,它负责的是怎么把用户端的请求送到php-fpm那去,这是个标准,Nginx实现了它。
  3. cgi是个数据交换的标准,fastcgi是它的plus版。php-cgi(注意中间的连接符)应该算是php-fpm的前辈,但是它本身是个cgi程序,不像php-fpm是管理器级别的,所以后来就慢慢被取代了(一开始php-fpm只是个插件,后来被核心收编了)。
  4. 基本就是上边说的那些。

(如果哪里有问题的还请大家指出来,谢谢)


另外建议看看这个问题下的答案~


看到两张流程图挺不错的,关于CGI和FastCGI的,转过来:

  • CGI
    191104434855332.png
  • FastCGI
    191104485636450.png

图片出处:Nginx + CGI/FastCGI + C/Cpp

用户请求->nginx(webserver)->fastcgi(nginx无法直接与php通讯,只能通过fastcgi接口通讯)->php-fpm(PHPFastCGI管理器)->php-cgi->php

谢邀
cgi 是一个协议,fastcgi是一个高级协议,这个就跟我们常用的http和https协议是一个道理.
php-cgi 负责解析cgi和fastcgi的程序而已
php-fpm 一个管理进程的进程管理器而已.他管理的是实现了能够解析cgi和fastcgi的程序而已,这个更通常的称之为sapi(服务器端应用编程端口)
现在我们来说说你的问题

1. nginx没有能力解析PHP,所以他通过实现fastcgi协议,然后把消息发送给我们的php-fpm,fpm就根据对应的模式来找寻对应的php-cgi来解析并返回给我们的nginx.至于一定要配置fpm么,答案是否定的.我可以通过转发给apache直接用cgi来解析也是可以的.
2. php-fpm和fastcgi都不管解析的事情,实际上负责解析的是我们的php-cgi
3. 至于php-fpm和fastcgi和php-cgi的关系我在上面已经说明了.
4. 他的说法是对的.但是php-fpm不是实现这个接口的东西.按照源码来说,正确实现这个解析的是php-cgi.

不懂的可以去看一下php7-internal这个作者所写的.写的挺不错的.
只有第4点,为撒会这么说.这个是根据php-fpm的源码来看的.php-fpm不会解析和处理请求.具体的请求处理都是在worker中,暂且称之为php-cgi吧.具体的fpm实现大概是这个样子的.

int main(int argc, char *argv[])
{
    sapi_startup(&cgi_sapi_module);    // 注册SAPI:将全局变量sapi_module设置为cgi_sapi_module
    ...
    fcgi_init();    // 初始化fastcgi协议,不解析,这回会返回一个值判断是否为fastcgi
    ...
    // 这里初始化fpm
    if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr)) {
        ...
    }
    ...
    if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {    // 启动模块
#ifdef ZTS
        tsrm_shutdown();
#endif
        return FPM_EXIT_SOFTWARE;
    }
    ...
    fcgi_fd = fpm_run(&max_requests);    // 获取worker进程,master将不再执行下面.由worker来处理我们的请求
    ...
    /* library is already initialized, now init our request */
    request = fpm_init_request(fcgi_fd);
}

// fpm_run函数
int fpm_run(int *max_requests) /* {{{ */
{
    struct fpm_worker_pool_s *wp;
    // 编译worker pool
    for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
        int is_parent;
        //调用fpm_children_make() fork子进程
        is_parent = fpm_children_create_initial(wp);
        if (!is_parent) {
            // fork 出的worker进程
            goto run_child;
        }
        /* handle error */
        if (is_parent == 2) {
            fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
            fpm_event_loop(1);
        }
    }
    // master进入event循环,不在往下走.
    fpm_event_loop(0);
run_child:
    fpm_cleanups_run(FPM_CLEANUP_CHILD);
    *max_requests = fpm_globals.max_requests;
    return fpm_globals.listening_socket;
}

暂且就说这么多吧,实际上还有一些例如phpinfo这个函数,是直接在php-fpm里面完成的,非常有技巧,一个常驻地址.

if (php_information) {    // 大约在/sapi/fpm/fpm_main.c 1746行左右
    cgi_sapi_module.phpinfo_as_text = 1;
    cgi_sapi_module.startup(&cgi_sapi_module);
    // 启用请求
    if (php_request_startup() == FAILURE) {
        SG(server_context) = NULL;
        php_module_shutdown();
        return FPM_EXIT_SOFTWARE;
    }
    SG(headers_sent) = 1;
    SG(request_info).no_headers = 1;
    // 直接就用0xFFFFFFFF这个地址了.
    php_print_info(0xFFFFFFFF);
    // 请求处理结束
    php_request_shutdown((void *) 0);
    fcgi_shutdown();
    exit_status = FPM_EXIT_OK;
    // 直接就跑到最后去了.
    goto out;
}

@熊猫桑 @上官元恒 你们肿么看 其实我也说的不是很对.大概是这个样子的.

从一个http请求说起:

1.client 通过http请求与服务器(nginx)建立一个一次性的连接
2.服务器收到请求后根据 .conf 文件里面的配置进行分发处理(如果配置是fastcgi 那就是fastcgi来处理)
3.fastcgi的本质是管理cgi使之更为高效率,所有这里会启动相对应的cgi程序,这里就是php解析器(zend)了
4.cgi接受数据处理完成后会返回给server
5.server再返回给client

这里插一个关于cgi的解析,是一个server与处理请求数据程序之间数据传输的一种标准,不特指某种语言https://zh.wikipedia.org/wiki...

然后再来看楼主的问题
1.PHP-FPM是一个PHP FastCGI管理器,所以不一定是fastcgi,你可以直接用cgi,但现在基本没有人这么干了
2.解析php程序的只有一个:ZEND 引擎!
3.PHP-FPM其实是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中;fastcgi = cgiEX
4.快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本

参考链接:
cgi wiki
fastcgi wiki
细说PHP-fpm

php-fpm 和fastcgi的关系类似于
浏览器和http的关系

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏