什麼是SAPI,FastCGI,PHP-FPM?學習PHP的必備知識
一個月前,我想在阿里雲 ECS 上部署一個 PHP 介面,發現伺服器沒有配置 PHP-FPM,所以立刻搗鼓了下,沒想到是最後花了一小時才搞定,事後分析了下,就是太急躁了,沒有使用正確的方法解決問題。
一個教訓:不管遇到任何事情,切記不能著急,仔細查閱文件才是正道。
廢話少說,趁著這次機會,我回顧了相關概念,即瞭解 Nginx、PHP-FPM 是如何協作的,介紹 PHP-FPM 和 PHP 之間的關係,SAPI 和 FastCGI 的區別,理解這些概念對於掌握 PHP 非常重要。
後續我也會針對PHP-FPM的配置做一些簡單的分享,比如分析本次遇到的問題以及原因,大家可以持續關注。至於為什麼不在一篇文章中全部寫完,主要考慮到乾巴巴羅列知識點,效果可能會比較差,針對特定問題描述的話,讀者印象會更深刻。
1:什麼是 SAPI
Server Application Programming Interface (SAPI) 是應用程式介面,對於 PHP 語言來說,它提供了很多 SAPI 介面,有了 SAPI,PHP 才有實際的用武之處。PHP 中最重要的 SAPI 是 PHP-FPM,提供給 Nginx Web 伺服器使用,換句話說,有了應用語言的 SAPI,才能擴充套件 Web 伺服器的功能。
對於 PHP 來說,它有以下一些 SAPI,如圖:

圖1
上圖就是 PHP5 相關的 SAPI,比較熟悉的就是 PHP-FPM,還有命令列的 php-cli,在 windows 下 SAPI 就是 php5apache2.dll。
2:FastCGI
對於 PHP-FPM 來說:
- 實現了 PHP 解析器
- 基於 FastCGI 協議,負責和 Web 伺服器(Nginx、Apache)通訊,那什麼是 FastCGI?
FastCGI is a binary protocol for interfacing interactive programs with a web server.
那麼我們來理解下 FastCGI 協議,簡單說來它就是 Web 伺服器和應用(比如 PHP)之間的一個互動標準,一個二進位制的協議,有了該協議,Nginx 和 PHP 之間就能夠互相通訊了,FastCGI 是 CGI 協議的一個升級。
光有 FastCGI 協議沒用,基於該協議,必須實現一個 SAPI 介面,PHP-FPM 就是一個 FastCGI 協議的實現,它能夠在一組關聯的請求中保持一個持久連線(同一個客戶請求由同一個 PHP-FPM 子程序處理),這個持久連線是由 PHP-FPM 處理的,而不是由 Web 伺服器處理的。
相比於 CGI 實現來說,FastCGI 實現能夠減少開銷,從而提升 Web 伺服器的處理能力。
一個 Web 請求如下圖:

圖2
Nginx 伺服器通過 FastCgi 協議,傳送環境變數和 HTTP 資料給 PHP-FPM,Nginx 和 PHP-FPM 之間可以通過 Unix domain socket 和 TCP connection 通訊。PHP-FPM 處理請求後,通過相同的連線返回資料給 Nginx。
通過上圖也可以看出,Nginx 和 PHP-FPM 是互相隔離的,也是非同步處理的,這也正是 Nginx 高效的原因,關於這方面可以通過一些專業文章去了解。Apache 最初使用 mod_php SAPI 處理請求(高度整合),這也是它緩慢的原因,但是現在 Apache 通過 FastCGI 協議也能和 PHP-FPM 通訊了。
3:PHP-FPM
PHP-FPM (FastCGI Process Manager) is an alternative FastCGI implementation for PHP。
PHP-FPM 剛才講了很多了,一方面它基於 FastCGI 協議實現了協議的功能,另外一方面它也集成了 PHP 解析器。
PHP-FPM 由一個主程序和多個子程序組成,主程序複製與 Web 伺服器通訊,接收 HTTP 請求,然後分配給子程序處理,子程序主要動態執行 PHP 語言,處理完成後,最終返回給 Web 伺服器。
PHP-FPM 有很多優點,比如:
- 能夠動態產生子程序(PHP解析器)。
- 能夠平滑啟動子程序。
- 有獨立的 php-fpm.conf 配置檔案,它基於 php.ini 配置檔案。
- fastcgi_finish_request() 功能支援,非常有用的特性。
總之,一句話,對於大型的 PHP 網站來說,PHP-FPM 做了足夠多的優化。
4:典型的 Nginx 和 PHP-FPM 配置
安裝和啟動 PHP-FPM 很簡單,以 Ubuntu 伺服器為例,執行如下命令即可:
$ apt-get install php5-fpm $ service php5-fpm start
通過 Nginx 配置檔案瞭解 Nginx 和 PHP-FPM 的互動細節:
server { listen 80 ; server_namewww.simplehttps.com ; location ~ \.php$ { root/usr/share/nginx/html; #fastcgi_pass127.0.0.1:9000; fastcgi_passunix:/var/run/www.simplehttps.com-fpm.sock; fastcgi_indexindex.php; includefastcgi_params; fastcgi_paramSCRIPT_FILENAME$document_root$fastcgi_script_name; } }
通過配置可以看出:
- Nginx 可以通過 9000 埠或本地 socket 檔案和 PHP-FPM 互動。
- fastcgi_params 包含了很多 Web 伺服器引數,比如 REMOTE_ADDR、QUERY_STRING 等等。
最後看下 PHP-FPM 檔案結構,如圖:

圖3
- conf.d:一些 php 通用擴充套件配置檔案。(屬於 PHP 的部分)
- php.ini:PHP 核心配置檔案。(屬於 PHP 的部分)
- php-fpm.conf:fpm 的主配置檔案,主要是 PHP-FPM 主程序使用。
- pool.d:該目錄下載入的配置檔案類似於 Web 伺服器中的虛擬主機配置,由 PHP-FPM 子程序處理。
關於 php-fpm.conf 和 pool.d 多說幾句:
(1)php-fpm.conf 是 PHP-FPM 的主配置檔案,都是全域性性配置,但配置項較少,比如包含 pid、error_log、events.mechanism 等引數,理解起來很簡單。
(2)pool.d 目錄可以包含多個虛擬主機配置檔案,由 php-fpm.conf 負責載入。
比如我一臺機器上 Nginx 配置了兩個虛擬主機,分別是 www.simplehttps.com 和 blog.simplehttps.com 。這兩個虛擬主機可以載入不同的 PHP-FPM,比如 www.simplehttps.com-fpm.sock 和 blog.simplehttps.com-fpm.sock ,那麼這兩個 PHP-FPM 可以使用不同的配置檔案(儲存在 pool.d 目錄下),配置檔案裡面的引數可以自由調整,以後我會寫文章詳細介紹。