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

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

我們知道nginx.conf中配需要配置fastCGI,php需要安裝php-fpm擴(kuò)展并啟動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是一個接口協(xié)議,是把nginx和php進(jìn)行解耦了。php-fpm是實現(xiàn)這個接口的工具。不知道這個理解是不是對的??

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

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

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

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

從一個http請求說起:

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

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

然后再來看樓主的問題
1.PHP-FPM是一個PHP FastCGI管理器,所以不一定是fastcgi,你可以直接用cgi,但現(xiàn)在基本沒有人這么干了
2.解析php程序的只有一個:ZEND 引擎!
3.PHP-FPM其實是PHP源代碼的一個補(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
編輯回答
安淺陌

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

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

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

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

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

int main(int argc, char *argv[])
{
    sapi_startup(&cgi_sapi_module);    // 注冊SAPI:將全局變量sapi_module設(shè)置為cgi_sapi_module
    ...
    fcgi_init();    // 初始化fastcgi協(xié)議,不解析,這回會返回一個值判斷是否為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進(jìn)程,master將不再執(zhí)行下面.由worker來處理我們的請求
    ...
    /* 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;
}

暫且就說這么多吧,實際上還有一些例如phpinfo這個函數(shù),是直接在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);
    // 請求處理結(jié)束
    php_request_shutdown((void *) 0);
    fcgi_shutdown();
    exit_status = FPM_EXIT_OK;
    // 直接就跑到最后去了.
    goto out;
}

@熊貓桑 @上官元恒 你們腫么看 其實我也說的不是很對.大概是這個樣子的.

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

那好,就說說我的理解:

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

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


另外建議看看這個問題下的答案~


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

  • CGI
    191104434855332.png
  • FastCGI
    191104485636450.png

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

2017年10月2日 00:23