PHP 在 Web Server 中的整合方式與效能比較:從 CGI 到 PHP-FPM 的演進
2025-07-11 17:18:52

因為多數網頁是 LAMP 架構,同事讓我研究了一下 PHP-FPM 相關的內容,在過程裡面發現了不少新知識,所以寫了這篇筆記。在正式介紹 PHP-FPM 之前,我會先介紹一下它誕生的背景,也就是 CGI !

CGI

CGI(Common Gateway Interface)並不是一個工具,而是早期 Web 技術中用來連接 Web 伺服器與應用程式(例如 PHP、Python)的橋接標準,它允許伺服器在收到請求後,將該請求傳遞給外部程式處理,並將結果返回給用戶端。

alt text

雖然 CGI 實作簡單、相容性高,但其實非常消耗資源且沒效率。在這篇文章有提到 mod_cgi 模組允許 Apache 收到 CGI 請求時,子程序會 fork 出一個新的 PHP-CGI process 再執行該 CGI,並將其輸出作為回應發送給客戶端,就像下圖所呈現的,每次瀏覽器發送一次請求, cgi 會替每一個請求建立一個 process 來解析 cgi 請求、進行 php 語法編譯。

alt text

在 Apache 1.3 中這沒問題,但在 Apache 2.0 中會影響效能。因為 Apache 2.0 採用執行緒型架構(threaded MPM),當多執行緒的程序進行 fork 時,會複製所有執行緒並立即終止除一個之外的其他執行緒。因此,後續發展出如 mod_php、FastCGI 與 PHP-FPM 等更高效的整合方式。

mod_php

為了解決剛剛說到傳統 CGI 的問題,mod_php 就誕生了。mod_php 是一個 Apache HTTP Server 的模組,將 PHP interpreter 內建於 Apache process 中,讓 Apache 能夠直接編譯 PHP 程式,處理 PHP 請求時不需要重複啟動外部程序,進而減少啟動與溝通的開銷。

alt text

看似解決了問題,但還是有以下缺點 :

  • mod_php 則在每個 Apache process 中都載入完整的 PHP Interpreter,造成記憶體等資源的浪費
  • 無法將 PHP 處理與 Apache 分開部署,PHP 版本切換也不方便
  • 因為 PHP 與 Apache 同個 process,mod_php 只可與 non-threaded 的 prefork MPM 搭配使用,無法在 threaded MPM (如 worker 或 event) 運作

FastCGI 的誕生? 和 php-fpm 的關係?

為了解決 CGI 造成的資源消耗問題,CGI 被改良並發展成不同形式,像是 FastCGI ( 協議,給 PHP語言使用 )、WSGI ( 給 Python )。我們可以從下面兩張圖看出 CGI 和 FastCGI 的差異,FastCGI process 會在伺服器啟動前先行啟動,且一旦啟動後,子 process 會持續在事件迴圈 / FCGI 協議接收區等待下一次請求,而不會因應單一請求而終止或立即重新 fork process。

alt text
alt text

為了實現 FastCGI 協議,發展出 php-fpm(FastCGI Process Manager)作為用戶請求和 PHP 透過 FastCGI 溝通的實作方式。和 CGI 與 php_mod 不同,php-fpm 是讓 PHP 以獨立 process 運作,這些 PHP process 會在 worker process pool 裡,由 master process 管理。

alt text

每個 process 並不是執行完請求就關閉,而是會先閒置,等待處理下一個 request,如果閒置太久,且已經太多 process 都閒置狀態才會關閉,所以不會有反覆啟動 processs 導致資源浪費。

Apache 使用 mod_php 與 php-fpm 的比較

比較項目 Apache + mod_php Apache + php-fpm
運作方式 PHP 嵌入 Apache process PHP 為獨立 process,透過 FastCGI 溝通
所需 MPM 只能搭配 prefork MPM 可搭配 worker 或 event MPM
記憶體使用 每個 process 含 PHP,記憶體高 靜態資源不需 PHP,記憶體更節省
安全性與彈性 同一使用者執行,無法隔離 可設定不同 user/pool,支援多版本與安全隔離
效能擴展性 有限 高,可彈性配置與自動調整 process 數量

Ref

Prev
2025-07-11 17:18:52