鍍金池/ 問答/PHP  Linux/ nginx中php-fpm 和fastcgi什么關(guān)系

nginx中php-fpm 和fastcgi什么關(guān)系

我們知道nginx.conf中配需要配置fastCGI,php需要安裝php-fpm擴(kuò)展并啟動(dòng)php-fpm守護(hù)進(jìn)程,nginx才可以解析php腳本。

直接說問題吧:
1.在Nginx中,是不是一定要配置php-fpm才能解析PHP?
2.到底解析PHP的是php-fpm還是fastcgi還是其他的東西?
3.php-fpm,fastcgi,phpcgi關(guān)系是什么?
4.有人說fastcgi是一個(gè)接口協(xié)議,是把nginx和php進(jìn)行解耦了。php-fpm是實(shí)現(xiàn)這個(gè)接口的工具。不知道這個(gè)理解是不是對(duì)的??

看了很多相關(guān)文章,感覺都不知道在說什么,沒有人講清楚的,希望各位自己的理解說說這些問題

回答
編輯回答
硬扛
  1. 配置了php-fpm也不能解析php文件,nginx只是個(gè)轉(zhuǎn)發(fā),fastcgi_pass就像proxy_pass一樣,轉(zhuǎn)發(fā)
  2. 解析PHP的是php-fpm
  3. php-cgi實(shí)現(xiàn)CGI(通用網(wǎng)關(guān)接口,來新請(qǐng)求就需要fork新進(jìn)程處理,效率低),php-fpm實(shí)現(xiàn)fastcgi(進(jìn)程一直存活)
  4. fastcgi是協(xié)議,php-fpm根據(jù)該協(xié)議數(shù)據(jù)進(jìn)程請(qǐng)求處理與響應(yīng),nginx根據(jù)該協(xié)議發(fā)出請(qǐng)求到php-fpm以及收取php-fpm返回的數(shù)據(jù)
2018年3月31日 13:24
編輯回答
鹿惑

php-fpm 和fastcgi的關(guān)系類似于
瀏覽器和http的關(guān)系

2017年1月22日 11:24
編輯回答
野橘

從一個(gè)http請(qǐng)求說起:

1.client 通過http請(qǐng)求與服務(wù)器(nginx)建立一個(gè)一次性的連接
2.服務(wù)器收到請(qǐng)求后根據(jù) .conf 文件里面的配置進(jìn)行分發(fā)處理(如果配置是fastcgi 那就是fastcgi來處理)
3.fastcgi的本質(zhì)是管理cgi使之更為高效率,所有這里會(huì)啟動(dòng)相對(duì)應(yīng)的cgi程序,這里就是php解析器(zend)了
4.cgi接受數(shù)據(jù)處理完成后會(huì)返回給server
5.server再返回給client

這里插一個(gè)關(guān)于cgi的解析,是一個(gè)server與處理請(qǐng)求數(shù)據(jù)程序之間數(shù)據(jù)傳輸?shù)囊环N標(biāo)準(zhǔn),不特指某種語言https://zh.wikipedia.org/wiki...

然后再來看樓主的問題
1.PHP-FPM是一個(gè)PHP FastCGI管理器,所以不一定是fastcgi,你可以直接用cgi,但現(xiàn)在基本沒有人這么干了
2.解析php程序的只有一個(gè):ZEND 引擎!
3.PHP-FPM其實(shí)是PHP源代碼的一個(gè)補(bǔ)丁,旨在將FastCGI進(jìn)程管理整合進(jìn)PHP包中;fastcgi = cgiEX
4.快速通用網(wǎng)關(guān)接口(Fast Common Gateway Interface/FastCGI)是一種讓交互程序與Web服務(wù)器通信的協(xié)議。FastCGI是早期通用網(wǎng)關(guān)接口(CGI)的增強(qiáng)版本

參考鏈接:
cgi wiki
fastcgi wiki
細(xì)說PHP-fpm

2017年1月21日 18:20
編輯回答
安淺陌

用戶請(qǐng)求->nginx(webserver)->fastcgi(nginx無法直接與php通訊,只能通過fastcgi接口通訊)->php-fpm(PHPFastCGI管理器)->php-cgi->php

2017年4月16日 13:46
編輯回答
久舊酒

謝邀
cgi 是一個(gè)協(xié)議,fastcgi是一個(gè)高級(jí)協(xié)議,這個(gè)就跟我們常用的http和https協(xié)議是一個(gè)道理.
php-cgi 負(fù)責(zé)解析cgi和fastcgi的程序而已
php-fpm 一個(gè)管理進(jìn)程的進(jìn)程管理器而已.他管理的是實(shí)現(xiàn)了能夠解析cgi和fastcgi的程序而已,這個(gè)更通常的稱之為sapi(服務(wù)器端應(yīng)用編程端口)
現(xiàn)在我們來說說你的問題

1. nginx沒有能力解析PHP,所以他通過實(shí)現(xiàn)fastcgi協(xié)議,然后把消息發(fā)送給我們的php-fpm,fpm就根據(jù)對(duì)應(yīng)的模式來找尋對(duì)應(yīng)的php-cgi來解析并返回給我們的nginx.至于一定要配置fpm么,答案是否定的.我可以通過轉(zhuǎn)發(fā)給apache直接用cgi來解析也是可以的.
2. php-fpm和fastcgi都不管解析的事情,實(shí)際上負(fù)責(zé)解析的是我們的php-cgi
3. 至于php-fpm和fastcgi和php-cgi的關(guān)系我在上面已經(jīng)說明了.
4. 他的說法是對(duì)的.但是php-fpm不是實(shí)現(xiàn)這個(gè)接口的東西.按照源碼來說,正確實(shí)現(xiàn)這個(gè)解析的是php-cgi.

不懂的可以去看一下php7-internal這個(gè)作者所寫的.寫的挺不錯(cuò)的.
只有第4點(diǎn),為撒會(huì)這么說.這個(gè)是根據(jù)php-fpm的源碼來看的.php-fpm不會(huì)解析和處理請(qǐng)求.具體的請(qǐng)求處理都是在worker中,暫且稱之為php-cgi吧.具體的fpm實(shí)現(xiàn)大概是這個(gè)樣子的.

int main(int argc, char *argv[])
{
    sapi_startup(&cgi_sapi_module);    // 注冊(cè)SAPI:將全局變量sapi_module設(shè)置為cgi_sapi_module
    ...
    fcgi_init();    // 初始化fastcgi協(xié)議,不解析,這回會(huì)返回一個(gè)值判斷是否為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) {    // 啟動(dòng)模塊
#ifdef ZTS
        tsrm_shutdown();
#endif
        return FPM_EXIT_SOFTWARE;
    }
    ...
    fcgi_fd = fpm_run(&max_requests);    // 獲取worker進(jìn)程,master將不再執(zhí)行下面.由worker來處理我們的請(qǐng)求
    ...
    /* library is already initialized, now init our request */
    request = fpm_init_request(fcgi_fd);
}

// fpm_run函數(shù)
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;
        //調(diào)用fpm_children_make() fork子進(jìn)程
        is_parent = fpm_children_create_initial(wp);
        if (!is_parent) {
            // fork 出的worker進(jìn)程
            goto run_child;
        }
        /* handle error */
        if (is_parent == 2) {
            fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
            fpm_event_loop(1);
        }
    }
    // master進(jìn)入event循環(huán),不在往下走.
    fpm_event_loop(0);
run_child:
    fpm_cleanups_run(FPM_CLEANUP_CHILD);
    *max_requests = fpm_globals.max_requests;
    return fpm_globals.listening_socket;
}

暫且就說這么多吧,實(shí)際上還有一些例如phpinfo這個(gè)函數(shù),是直接在php-fpm里面完成的,非常有技巧,一個(gè)常駐地址.

if (php_information) {    // 大約在/sapi/fpm/fpm_main.c 1746行左右
    cgi_sapi_module.phpinfo_as_text = 1;
    cgi_sapi_module.startup(&cgi_sapi_module);
    // 啟用請(qǐng)求
    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這個(gè)地址了.
    php_print_info(0xFFFFFFFF);
    // 請(qǐng)求處理結(jié)束
    php_request_shutdown((void *) 0);
    fcgi_shutdown();
    exit_status = FPM_EXIT_OK;
    // 直接就跑到最后去了.
    goto out;
}

@熊貓桑 @上官元恒 你們腫么看 其實(shí)我也說的不是很對(duì).大概是這個(gè)樣子的.

2017年4月29日 20:36
編輯回答
醉淸風(fēng)

那好,就說說我的理解:

  1. Nginx本身無法解析php,所以它需要一個(gè)執(zhí)行環(huán)境(runtime)來解析它,這個(gè)運(yùn)行時(shí)環(huán)境是zend,php-fpm負(fù)責(zé)接受nginx的請(qǐng)求并傳遞給zend。
  2. fastcgi不管解析的事,它負(fù)責(zé)的是怎么把用戶端的請(qǐng)求送到php-fpm那去,這是個(gè)標(biāo)準(zhǔn),Nginx實(shí)現(xiàn)了它。
  3. cgi是個(gè)數(shù)據(jù)交換的標(biāo)準(zhǔn),fastcgi是它的plus版。php-cgi(注意中間的連接符)應(yīng)該算是php-fpm的前輩,但是它本身是個(gè)cgi程序,不像php-fpm是管理器級(jí)別的,所以后來就慢慢被取代了(一開始php-fpm只是個(gè)插件,后來被核心收編了)。
  4. 基本就是上邊說的那些。

(如果哪里有問題的還請(qǐng)大家指出來,謝謝)


另外建議看看這個(gè)問題下的答案~


看到兩張流程圖挺不錯(cuò)的,關(guān)于CGI和FastCGI的,轉(zhuǎn)過來:

  • CGI
    191104434855332.png
  • FastCGI
    191104485636450.png

圖片出處:Nginx + CGI/FastCGI + C/Cpp

2017年10月2日 00:23