為什麼要優化php-fpm?如何優化?

2022-09-19 14:00:29

php零基礎到就業直播視訊課:進入學習

PHP是無處不在的,可以說是網際網路 Web 應用上使用最廣泛的語言。

然而,它的高效能並不為人所知,尤其是在涉及到高並行系統時。這就是為什麼對於這樣特殊的用例,正在被 Node (是的,我知道,它不是一種語言)、Go 和 Elixir 等語言接管。

也就是說,您可以做很多事情來改進伺服器上的 PHP 效能。本文主要關注 php-fpm 方面的內容,如果您使用Nginx,這是在伺服器上的預設設定。

如果你知道 php-fpm 是什麼,請直接跳到優化部分。

什麼是 php-fpm?

許多開發人員對 DevOps 方面的知識不太感興趣,即使是那些對此感興趣的開發人員,也極少有人知道它的底層原理。有趣的是,當瀏覽器傳送一個請求到執行 PHP 的伺服器上時,PHP 也不是最先進行處理請求的服務;而是,HTTP 伺服器,Apache 和 Nginx 是其中最主要的兩個。「web 伺服器」決定如何與 PHP 進行通訊,然後傳遞請求的型別,資料和頭部資訊到 PHP 程序。

PHP

上圖是 PHP 專案的請求-響應生命週期(圖片來源: ProinerTech)

在現代 PHP 應用中,「find file」部分即為 index.php 檔案,它是在伺服器組態檔中設定的用於處理所有請求的代理。

如今,Web 伺服器究竟如何連線 PHP 正在進化,如果我們要深入研究所有細節,這篇文章的長度將激增。但粗略來說, 在 Apache 作為 Web 伺服器首選的時間段,PHP 是作為包含在伺服器內部的模組。

所以每當一個請求被接收,伺服器將開啟一個新的程序, 它將自動包含 PHP 和執行請求。這個方法被稱作mod_php,「PHP作為一個模組」的縮寫。這種方法有其侷限性,而 Nginx 和 php-fpm 克服了它。

php-fpm中,管理 PHP 的責任在於伺服器內部的 PHP 程式。換言之, Web 伺服器 (Nginx, 在本例中), 不在乎 PHP 在哪和怎樣執行的,只要它知道如何傳送和接收資料即可。如果需要,在這種情況下,您可以將PHP視為另一臺伺服器,它管理傳入請求的某些子PHP程序(因此,我們將請求送到伺服器,該請求由伺服器接收並傳遞到伺服器 — —太瘋狂了!:-P)。

如果你用過Nginx,你會看到這些程式碼:

     location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

對於這一行:fastcgi_pass unix:/run/php/php7.2-fpm.sock;,它告訴Nginx通過 php7.2-fpm.socksocket與php程序通訊。因此,對於每個傳入的請求,Nginx都通過這個檔案寫入資料,在接收到輸出後,將其傳送回瀏覽器。

我必須再次強調,對於如何執行這不是最完整或者最準確的,但對於大多數 DevOps 任務是完全準確的。

除此之外,讓我們回顧一下到目前為止所學到的東西:

  • PHP不會直接接收瀏覽器傳送的請求。像 Nginx 這種 Web 伺服器首先會攔截它。
  • Web 伺服器知道如何連線到PHP程序,並將所有請求資料(貼上所有內容)傳遞到 PHP 上。
  • PHP 完成其職責後,會將響應傳送回 Web 伺服器,然後將其傳送回使用者端(在大多數情況下為瀏覽器)。

流程圖如下:

PHP

PHP 和 Nginx 如何協同工作? (圖片來源:資料狗)

到目前為止都不錯, 那麼關鍵問題來了:PHP-FPM到底是什麼呢?

PHP 中的 FPM 代表 「快速程序管理器」, 花式解釋就是說,在伺服器上執行的 PHP 並不是單個程序,而是由這個 FPM 程序管理器派生、控制和終止的一些PHP 程序。web伺服器將請求傳遞給的就是這個程序管理器。

PHP-FPM 本身就是一個完整的兔子洞,所以如果您願意,可以隨意探索,但是對於我們的目的,這些解釋就足夠啦。 ?

為什麼要優化php-fpm?

一般在正常執行的情況下,為什麼要考慮優化呢? 為什麼不將事物保持原樣。

具有諷刺意味的是,一般我為大多數用例提供建議的話。 如果您的設定執行良好,並且沒有特殊用例,請使用預設設定。 但是,如果您希望擴充套件一臺機器之外的能力,那麼從一臺機器中擠出最大的處理能力是必不可少的,因為它可以將您伺服器的花費減少一半(甚至更多!)。

要說明的另一件事情是,Nginx是為處理巨大的工作負載而構建的。 它能夠同時處理成千上萬的連線,但是如果您的PHP設定不合理,那麼您將浪費很多資源,因為Nginx必須等待PHP完成當前處理之後才可以接受下一個請求,最終Nginx不能為您的服務提供任何優勢!

所以,接下來讓我們看看嘗試優化 php-fpm 時我們到底要優化什麼。

如何優化 PHP-FPM ?

php-fpm 的組態檔在不同伺服器上的位置可能不同,因此您需要做一些調查來確定它的位置。在 UNIX 上,你可以使用 find 命令。在我的 Ubuntu 上,它的路徑是 /etc/php/7.2/fpm/php-fpm.conf 。當然,7.2是我正在執行的 PHP 版本。

下面是這個檔案的前幾行程式碼:

;;;;;;;;;;;;;;;;;;;;;
; FPM Configuration ;
;;;;;;;;;;;;;;;;;;;;;

; All relative paths in this configuration file are relative to PHP's install
; prefix (/usr). This prefix can be dynamically changed by using the
; '-p' argument from the command line.

;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;

[global]
; Pid file
; Note: the default prefix is /var
; Default Value: none
pid = /run/php/php7.2-fpm.pid

; Error log file
; If it's set to "syslog", log is sent to syslogd instead of being written
; into a local file.
; Note: the default prefix is /var
; Default Value: log/php-fpm.log
error_log = /var/log/php7.2-fpm.log

很明顯:這一行 pid = /run/php/php7.2-fpm.pid 告訴我們哪個檔案包含了 php-fpm 程序的程序 id。

我們還看到 /var/log/php7.2-fpm.logphp-fpm 儲存紀錄檔的地方。

在這個檔案中,像下面這樣新增三個變數:

emergency_restart_threshold 10
emergency_restart_interval 1m
process_control_timeout 10s

前兩個設定是警告性的,它們告訴 php-fpm 程序,如果10個子程序在一分鐘內失敗,主 php-fpm 程序應該重新啟動自己。

這聽起來可能不夠穩健,但是 PHP 是一個短暫的程序,它會洩漏記憶體,所以在出現高故障時重新啟動主程序可以解決很多問題。

第三個選項是 process_control_timeout,它告訴子程序在執行從父程序接收到的訊號之前需要等待這麼長的時間。這個設定是非常有用的。例如,當父程序傳送終止訊號時,子程序正在處理某些事情的時候。十秒的時間,他們會有一個更好的機會完成任務並且優雅地退出。

令人驚訝的是,這 不是 php-fpm 的核心設定!這是因為,為了 web 請求服務,php-fpm 建立了一個新的程序池,它將具有一個單獨的設定。在我的例子中,程序池的名稱是 www,我想編輯的檔案是 /etc/php/7.2/fpm/pool.d/www.conf

讓我們來看看檔案的內容:

; Start a new pool named 'www'.
; the variable $pool can be used in any directive and will be replaced by the
; pool name ('www' here)
[www]

; Per pool prefix
; It only applies on the following directives:
; - 'access.log'
; - 'slowlog'
; - 'listen' (unixsocket)
; - 'chroot'
; - 'chdir'
; - 'php_values'
; - 'php_admin_values'
; When not set, the global prefix (or /usr) applies instead.
; Note: This directive can also be relative to the global prefix.
; Default Value: none
;prefix = /path/to/pools/$pool

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
user = www-data
group = www-data

快速瀏覽一下上面程式碼片段的末尾,您就會明白為什麼伺服器程序以 www-data 的形式執行了。如果您在設定網站時遇到檔案許可權問題,您可能要將目錄的所有者或組更改為 www-data,從而允許PHP程序寫入紀錄檔檔案和上傳檔案等。

最後,我們到達了問題的根源,流程管理器 (pm) 設定。一般情況下,預設值是這樣的:

pm = dynamic
pm.max_children = 5
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 200

那麼,這裡的 「dynamic(動態)」是什麼意思呢?我認為官方檔案最好地解釋了這一點(我的意思是,這應該已經是您正在編輯的檔案的一部分,但是我在這裡複製了它,以防它不是):

; Choose how the process manager will control the number of child processes.
; Possible Values:
;   static  - a fixed number (pm.max_children) of child processes;
;   dynamic - the number of child processes are set dynamically based on the
;             following directives. With this process management, there will be
;             always at least 1 children.
;             pm.max_children      - the maximum number of children that can
;                                    be alive at the same time.
;             pm.start_servers     - the number of children created on startup.
;             pm.min_spare_servers - the minimum number of children in 'idle'
;                                    state (waiting to process). If the number
;                                    of 'idle' processes is less than this
;                                    number then some children will be created.
;             pm.max_spare_servers - the maximum number of children in 'idle'
;                                    state (waiting to process). If the number
;                                    of 'idle' processes is greater than this
;                                    number then some children will be killed.
;  ondemand - no children are created at startup. Children will be forked when
;             new requests will connect. The following parameter are used:
;             pm.max_children           - the maximum number of children that
;                                         can be alive at the same time.
;             pm.process_idle_timeout   - The number of seconds after which
;                                         an idle process will be killed.
; Note: This value is mandatory.

由此可見,有三個可用值:

  • Static: 無論什麼情況,都會保持一個固定的PHP程序數量。
  • Dynamic: 我們需要指定php-fpm在任何給定時間點會保持活動的最小以及最大程序數量。
  • ondemand: 按照需求建立和銷燬程序。

那這些設定有什麼影響呢?

簡而言之,如果你有個小流量的網站,「dynamic」設定在大多數時間內都是一種資源的浪費。假設你的pm.min_spare_servers設定成了3,那會有三個PHP程序會被建立並保持執行,甚至是網站沒有流量時。這種情況下,「ondemand」 就是個更好的選擇, 可以讓系統決定何時啟動新的程序。

另一方面, 大流量 或者必須快速響應的網站將在這種情況下被懲罰。 最好避免建立新的 PHP 程序的額外開銷,使其成為池的一部分並對其進行監控。

使用 pm = static 固定子程序的數量,使最大的系統資源用於服務請求而不是管理 PHP。假如你確定走這條路,注意它有其指導方針和陷阱.關於它的一篇相當密集但非常有用的文章是 這篇 。

寫在最後

由於有關網路效能的文章可能會引發爭論或使人們感到困惑,因此在結束本文之前,我覺得需要講幾句話。 效能調優既涉及系統知識,也涉及猜測和技巧。

即使您完全瞭解 php-fpm 的所有設定,也無法保證成功。 如果您不瞭解 php-fpm 的存在,那麼您就不必浪費時間擔心它。 繼續做您已經在做的事情並繼續下去。

同時,儘可能不讓結果變得很戲劇性。 是的,您可以通過從頭開始重新編譯 PHP 並刪除所有不需要的模組來獲得更好的效能,但是這種方法在生產環境中不夠明智。 優化某些內容的整個想法是檢視您的需求是否與預設值不同(它們很少這樣做!),並根據需要進行較小的更改。

英文原文地址:https://geekflare.com/php-fpm-optimization/

推薦學習:《》

以上就是為什麼要優化php-fpm?如何優化?的詳細內容,更多請關注TW511.COM其它相關文章!