PHP 基礎:PHP-FPM 與 mod_php?


Why PHP-FPM?

PHP-FPM(FastCGI Process Manager)之所以在近年來成為主流,主要歸因於其在效能、資源管理和靈活性方面的顯著優勢。相較於傳統的 mod_php,PHP-FPM 採用了獨立的 process 管理機制,使得 PHP Interpreter 可以與網頁伺服器分離運作。

  • 這種架構允許更精細的資源控制,能夠根據網站流量動態調整 PHP process 數量,大幅提升了高度並行需求環境下的處理能力。
  • PHP-FPM 的 process 隔離特性也增強了安全性,降低了單一腳本錯誤影響整個伺服器的風險。
  • PHP-FPM 支援多個獨立的 process pool,讓開發者能為不同的專案或客戶設置專屬的 PHP 環境,這在多用戶架構或需要嚴格資源隔離的場景中特別有用。
  • PHP-FPM 與 Apache 以及 Nginx 在整合上相當絲滑。
  • PHP-FPM 也簡化了 PHP 版本管理和升級流程,允許在不影響整個網頁伺服器的情況下更新 PHP。

跟 mod_php 的比較

  • 資源管理:PHP-FPM 能夠更有效地管理系統資源。它可以根據負載動態調整 process 數量,而 mod_php 則在每個 Apache process 中都載入完整的 PHP Interpreter,即使該 process 可能不處理 PHP 請求(意思是,就算 HTTP request 只是請求圖片、CSS以及 JS這類靜態檔案也會導致每一隻 Apache process都載入完整的 PHP Interpreter)。
  • 記憶體使用:PHP-FPM 通常比 mod_php 更節省記憶體。在 mod_php 中,每個 Apache process 都包含 PHP Interpreter,這會導致較高的記憶體使用。
  • Process 隔離:PHP-FPM 提供更好的 process 隔離。每個 PHP 腳本在獨立的進程中運行,一個腳本的問題不太可能影響到其他腳本或整個伺服器。
  • 靈活性:PHP-FPM 允許為不同的網站或應用程式設置不同的 process pool,每個 pool 可以有自己的 PHP 設定。這在 mod_php 中是難以實現的。
  • 安全性:由於更好的 process 隔離,PHP-FPM 在安全性方面有優勢。不同網站可以使用不同的使用者權限運行。
  • 效能:在高度並行需求的環境下,PHP-FPM 表現更佳。它可以更有效地處理大量並發請求。
  • 錯誤處理:PHP-FPM 可以在不影響其他請求的情況下重新啟動單個 process,這使得錯誤恢復更加絲滑。
  • 升級和維護:使用 PHP-FPM 可以在不重新啟動整個 Web 伺服器的情況下更新 PHP 版本或設定。
  • 監控和調試:PHP-FPM 提供了更多的監控選項,可以更容易地追蹤和分析性能問題。
  • 適應性:PHP-FPM 更適合容器化和微服務架構,這在現代雲端環境中很重要。
  • 長時間運行的進程:PHP-FPM 更適合處理長時間運行的 PHP 腳本,而不會阻塞其他請求。

安裝 PHP-FMP

sudo apt update

# 執行後,系統會連線到設定好的套件庫(通常是 Ubuntu 的官方伺服器或是台灣的 Mirror),下載最新的套件資訊,但不會安裝或升級任何套件。這個步驟讓系統知道有哪些套件可以更新,為後續的升級做準備。

sudo apt upgrade

# 這個指令會根據剛才更新的套件資訊,升級系統中已安裝的套件到最新版本。

安裝必要的 libapache2-mod-fcgid 以及 php8.1-fpm 套件。

sudo apt install libapache2-mod-fcgid php8.1-fpm

libapache2-mod-fcgid

這 package 提供了 FastCGI 的實作,FastCGI 是一種協議,允許網頁伺服器與外部程序(如 PHP)進行高效的溝通,相較於傳統的 CGI,它能夠顯著提升性能。這個模組使 Apache 能夠將請求轉發給 FastCGI 處理程序,從而實現更高效的資源利用和彈性。

php8.1-fpm

PHP 8.1 版本的 FastCGI Process Manager(FPM)。PHP-FPM 是 PHP FastCGI 實作,它管理 PHP process pool,能夠動態調整 process 數量以應對不同的負載情況、允許不同網站使用不同的配置、更好的隔離性和安全性。

PHP-FPM 的版本應該與系統中的 PHP 版本相匹配,所以在安裝前務必先確認目前 production 環境中 PHP的版本號。

php -v

以我測試機上的 PHP為例,它的版本號是 PHP 8.1.x

PHP 8.1.2-1ubuntu2.18 (cli) (built: Jun 14 2024 15:52:55) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.2-1ubuntu2.18, Copyright (c), by Zend Technologies

安裝完成後,您可以檢查 PHP-FPM 的狀態:

sudo systemctl status php8.1-fpm

CLI 應該會顯示以下資訊。

● php8.1-fpm.service - The PHP 8.1 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.1-fpm.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2024-09-14 11:55:48 UTC; 10min ago
       Docs: man:php-fpm8.1(8)
   Main PID: 4190221 (php-fpm8.1)
     Status: "Processes active: 0, idle: 3, Requests: 4, slow: 0, Traffic: 0req/sec"
      Tasks: 4 (limit: 9498)
     Memory: 146.9M
        CPU: 3.545s
     CGroup: /system.slice/php8.1-fpm.service
             ├─4190221 "php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
             ├─4190227 "php-fpm: pool www" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
             ├─4190228 "php-fpm: pool www" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
             └─4191279 "php-fpm: pool www" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""

如果服務沒有自動啟動,我們可以手動啟動

sudo systemctl start php8.1-fpm

設定開機自動啟動

sudo systemctl enable php8.1-fpm

接著需要用以下 CLI命令在 Apache2 網頁伺服器中啟用兩個關鍵模組。首先,proxy_fcgi 模組啟用 FastCGI 代理功能,允許 Apache 將請求轉發給外部 FastCGI 服務器(如 PHP-FPM)處理。

setenvif 模組允許根據請求的特定條件動態設置環境變數,提供了更精細的伺服器設定控制

這兩個模組的組合是 Apache 和 PHP-FPM 整合的必要基礎,啟用這些模組後,管理者需要重新載入 Apache 配置以使更改生效,通常通過重啟 Apache 服務來完成。

sudo a2enmod proxy_fcgi setenvif

接著我們可以用以下這段 CLI來檢查 PHP-FPM 的運作狀況,這行指令用於查看 PHP-FPM 8.1 版本的 Unix domain socket 檔案的詳細資訊,當你執行這個指令時,系統會顯示這個 socket 檔案的權限設定、擁有者、群組、最後修改時間等資訊。這個檢查可以幫助我們進行系統維護或除錯,它可以快速告訴我們 PHP-FPM 服務是否正常運作。如果這個檔案存在而且權限正確,通常代表 PHP-FPM 服務已經順利啟動;反之,如果檔案不見了或權限有問題,那可能就得進一步檢查 PHP-FPM 的設定或服務狀態了。在設定 Apache 或 Nginx 與 PHP-FPM 整合時,確保這個 socket 檔案的存在和可訪問性是很關鍵的一步,因為 Web 伺服器就是透過這個 socket 檔案來與 PHP-FPM 進行溝通的。

ls -l /var/run/php/php8.1-fpm.sock

正個設置如果正常的話應該會看到以下的 CLI輸出。

srw-rw---- 1 www-data www-data 0 Sep 14 11:55 /var/run/php/php8.1-fpm.sock

接著在 Virtual Host設定檔中加入以下設定:

sudo vim /etc/apache2/sites-available/xxx.botsnova.com.conf

<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php/php8.1-fpm.sock|fcgi://localhost"
</FilesMatch>

上述設定的作用是:

  • 當 Apache 收到對 .php 檔案的請求時,它會將 Requests 轉發給 PHP-FPM 處理
  • 通訊通過 Unix domain socket 進行,這比 TCP socket 更快速、更安全
  • 使用 FastCGI 協議,允許 PHP-FPM 進程持續運行,提高效能
  • 這種設定將 PHP 處理與 Apache 分離,提高了整體系統的效能和穩定性。
<VirtualHost *:443>
        DocumentRoot /home/ubuntu/wwwdata/sites/xxx.botsnova.com
        ServerName xxx.botsnova.com
        ServerAlias xxx.botsnova.com
        <Directory /home/ubuntu/wwwdata/sites/xxx.botsnova.com>
                Require all granted
                Options -Indexes +FollowSymLinks
                AllowOverride All
        </Directory>

        # 新增以下設定來處理 PHP 文件
        <FilesMatch \.php$>
            SetHandler "proxy:unix:/var/run/php/php8.1-fpm.sock|fcgi://localhost"
        </FilesMatch>

        CustomLog ${APACHE_LOG_DIR}/xxx.botsnova.com.access.log combined
        ErrorLog  ${APACHE_LOG_DIR}/xxx.botsnova.com.error.log

        SSLCertificateFile /etc/letsencrypt/live/xxx.botsnova.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/xxx.botsnova.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>

最後重新載入更新後的 Apache設定

sudo systemctl reload apache2

確認目前網站使用的是哪一個 Server API

我們使用 phpinfo() 檢視設定應該會看到 Server API 為 FPM/FastCGI。


如果想要讓某一個特定的 Virtual Host 使用 mod_php 可以如下設定:

<VirtualHost *:443>
        DocumentRoot "/home/ubuntu/wwwdata/sites/xxx.botsnova.com"
        ServerName xxx.botsnova.com
        ServerAlias xxx.botsnova.com
        <Directory /home/ubuntu/wwwdata/sites/xxx.botsnova.com>
                Require all granted
                Options -Indexes +FollowSymLinks
                AllowOverride All
        </Directory>

        <FilesMatch \.php$>
                SetHandler application/x-httpd-php
        </FilesMatch>

        CustomLog ${APACHE_LOG_DIR}/xxx.botsnova.com.log combined
        ErrorLog  ${APACHE_LOG_DIR}/xxx.botsnova.com.error.log

        SSLCertificateFile /etc/letsencrypt/live/xxx.botsnova.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/xxx.botsnova.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>

重新啟動 Apache

sudo systemctl restart apache2

使用 phpinfo() 檢視設定應該會看到 Server API 為 Apache 2.0 Handler。


經過上面的說明我們可以知道,透過在不同的 Virtual Host 進行設定去使用不同的 Server API,我們可以自由的決定何時要使用 PHP-FPM 以及 php_mod。

基本設定

最後我們需要稍微調整一下 PHP-FMP的一些基本設定,不然很容易連 WordPress都執行不起來。

sudo vim /etc/php/8.1/fpm/pool.d/www.conf

# PHP-FMP設定檔

通常我用來 host WordPress 的機器我會開 8GB 的 RAM,在這樣的條件下我通常都是使用以下的配置值。

php_admin_value[memory_limit] = 512M

# 這對大多數 PHP 應用來說應該足夠,同時也留有足夠的空間給系統和其他服務使用。這個設定允許更複雜的 PHP 操作,但也要注意不要設置得太高,以免單一請求消耗過多資源。

php_admin_value[upload_max_filesize] = 128M
php_admin_value[post_max_size] = 128M

# 這兩個值通常設定為相同,而且 post_max_size 應該稍大於或等於 upload_max_filesize。128MB 對於大多數上傳需求來說應該足夠,同時不會對系統造成過大壓力。這個大小適合上傳較大的文件,如高解析度圖片或中等大小的影片。

php_admin_value[max_execution_time] = 300
php_admin_value[max_input_time] = 300

# 300 秒(~5 分鐘)的執行時間對於大多數 PHP 來說是合理的。這個設定允許執行較複雜的操作,同時也防止腳本無限期執行。對於需要更長時間的任務,建議使用後台作業或分割處理。

最後重新載入 Apache 設定,整個 Apache + PHP-FPM的設置就算大功告成了!

sudo systemctl reload apache2

Apache sites-available & sites-enabled?

最後我發現很多同學們都沒有弄清楚 Apache2 的 sites-available/sites-enabled/ 這兩個目錄間的關聯性,我以下額外做些補充。

a2ensite:這個指令用於啟用位於 sites-available/ 目錄中的 Virtual Host 設定檔。當你執行 a2ensite 時,它會在 sites-enabled/ 目錄中建立一個 Symbolic Link,指向 sites-available/ 中的原始設定檔。這個動作告訴 Apache2,你想要啟用這個特定的虛擬目錄設定。舉例來說,如果你有一個叫做 xxx.botsnova.com.conf 的設定檔在 sites-available/ 中,執行 sudo a2ensite mywebsite 會在 sites-enabled/ 中創建一個指向它的 Symbolic Link。

sudo a2ensite xxx.botsnova.com.conf

# 啟用 xxx.botsnova.com.conf

sudo a2dissite xxx.botsnova.com.conf

# 停用 xxx.botsnova.com.conf

a2dissite:相對地,a2dissite 用於停用一個已啟用的虛擬目錄設定。它會移除 sites-enabled/ 目錄中的 Symbolic Link,但不會刪除 sites-available/ 中的原始設定檔。這樣做可以暫時停用一個網站,而不需要完全刪除其設定。如果之後你想重新啟用這個網站,原始設定檔仍然保存在 sites-available/ 中,隨時可以再次啟用。

這兩個指令的關聯性:a2ensitea2dissite 指令實際上是一種管理 Symbolic Link 的簡潔方式。它們讓系統管理員可以輕鬆地控制哪些網站設定是活躍的,而不需要手動處理 Symbolic Link。這種方法提供了一個清晰的結構,讓你可以看到哪些網站設定目前是啟用的(在 sites-enabled/ 中),以及有哪些可用的設定(在 sites-available/ 中)。

使用這些指令的好處:這種設計提供了極大的彈性。你可以保留多個網站的設定檔在 sites-available/ 中,但只啟用你當前需要的。這對於管理多個虛擬主機或在 dev 和 production 環境之間切換特別有用。此外,它也簡化了備份和版本控制,因為所有的設定檔都集中在一個地方。

每次使用這些指令後,你需要重新載入或重啟 Apache2 服務,以使更改生效。這可以通過執行 sudo systemctl reload apache2sudo systemctl restart apache2 來完成。

使用 ps aux 指令檢視 PHP-FPM 運行狀況

ubuntu@ip-172-31-31-181:~$ ps aux | grep php-fpm
root        2932  0.0  0.4 241180 37156 ?        Ss   Sep14   0:05 php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)
www-data    2933  0.1  2.3 384300 191076 ?       S    Sep14   1:20 php-fpm: pool www
www-data    2934  0.1  2.3 380544 187896 ?       S    Sep14   1:20 php-fpm: pool www
www-data    2935  0.1  2.3 388256 192164 ?       S    Sep14   1:21 php-fpm: pool www
www-data    2936  0.1  2.4 396780 201252 ?       S    Sep14   1:24 php-fpm: pool www
www-data    2937  0.1  2.3 385772 190292 ?       S    Sep14   1:23 php-fpm: pool www
www-data    2938  0.1  2.3 381740 187248 ?       S    Sep14   1:23 php-fpm: pool www
www-data    2939  0.1  2.2 382172 186348 ?       S    Sep14   1:21 php-fpm: pool www
www-data    2940  0.1  2.3 381872 187156 ?       S    Sep14   1:21 php-fpm: pool www
www-data    2941  0.1  2.2 383968 186568 ?       S    Sep14   1:20 php-fpm: pool www
www-data    2942  0.1  2.2 381928 185824 ?       S    Sep14   1:19 php-fpm: pool www
www-data    2999  0.1  2.3 386232 189012 ?       S    Sep14   1:24 php-fpm: pool www
www-data    3607  0.1  2.3 388096 190648 ?       S    Sep14   1:20 php-fpm: pool www
www-data    4582  0.1  2.3 391876 194724 ?       S    Sep14   1:12 php-fpm: pool www
www-data    4782  0.1  2.3 387920 190544 ?       S    Sep14   1:05 php-fpm: pool www
www-data    5523  0.1  2.2 381376 184808 ?       S    Sep14   0:59 php-fpm: pool www
www-data    5644  0.1  2.2 379748 181668 ?       S    Sep14   0:58 php-fpm: pool www
www-data    5646  0.1  2.4 393716 197244 ?       S    Sep14   0:59 php-fpm: pool www
www-data    5647  0.1  2.2 381928 183104 ?       S    Sep14   0:55 php-fpm: pool www
www-data    5650  0.1  2.3 389704 192828 ?       S    Sep14   0:55 php-fpm: pool www
www-data    5651  0.1  2.2 381464 184316 ?       S    Sep14   0:58 php-fpm: pool www
www-data    5652  0.1  2.3 387592 188712 ?       S    Sep14   1:02 php-fpm: pool www
www-data    5653  0.1  2.3 385888 189316 ?       S    Sep14   0:56 php-fpm: pool www
www-data    5659  0.1  2.1 339592 171980 ?       S    Sep14   0:59 php-fpm: pool www
www-data   13074  0.1  2.1 344596 176712 ?       S    11:06   0:08 php-fpm: pool www
www-data   13083  0.1  2.2 350788 182100 ?       S    11:06   0:09 php-fpm: pool www
ubuntu     13851  0.0  0.0   7008  2304 pts/0    R+   12:31   0:00 grep --color=auto php-fpm

這個輸出提供了 PHP-FPM(PHP FastCGI Process Manager)在 Ubuntu 系統上運行情況的詳細資訊。

首先,我們可以看到一個主要的 master process,由 root 用戶運行,PID 為 2932。這個 master process 負責管理整個 PHP-FPM 系統,包括讀取配置文件(在這裡是 /etc/php/8.1/fpm/php-fpm.conf),啟動和管理 worker processes。master process 使用相對較少的記憶體(37156 KB 的 RSS),這是正常的,因為它主要負責協調而不是處理實際的 PHP 請求。

接下來,我們看到許多由 www-data 用戶運行的 worker processes。這些是實際處理 PHP 請求的 process。每個 worker 都屬於名為 “www” 的 process pool。這個 pool 是系統的 default pool,用於處理大部分或所有的 PHP 請求。每個 worker 使用大約 180-200 MB 的記憶體(RSS 列),這個數值取決於它們處理的腳本複雜度和 PHP 配置。

值得注意的是,所有這些 worker processes 都在 9 月 14 日啟動,表明系統穩定運行了相當長的時間。每個 worker 的 CPU 時間(最後一列)略有不同,範圍從約 55 秒到 1 分 24 秒不等,這反映了它們處理請求的數量和複雜度可能有所不同。

我們還可以看到兩個較新的 worker processes(PID 13074 和 13083),它們是在當天(11:06)啟動的。這可能表示系統根據負載動態增加了 worker 數量,這是 PHP-FPM 的一個重要特性。

需要注意的是每個人看到的資訊都會不一樣,我這是公司的實驗機器上看到的執行概況。

Leave a Comment

Your email address will not be published. Required fields are marked *