PHP-FPM 調優:使用 ‘pm static’ 來最大化你的伺服器負載能力
讓我們來迅速瞭解一下怎樣設定 PHP-FPM,以便達到高吞吐,低延遲以及穩定的使用 CPU 和記憶體的完美狀態。在預設的情況下,大多數設定都將 PHP-FPM PM(程序管理器)設定為 dynamic
,或者當你有可用記憶體的問題時常建議你使用 ondemand
。接下來,讓我們根據 php.net 的官方文件來比較一下這兩個管理選項和我最常用的設定 —— static
之間的區別:
-
pm = dynamic:子程序的數量是根據以下指令來動態生成的:
pm.max_children
,pm.start_servers
,pm.min_spare_servers
,pm.max_spare_servers
-
pm = ondemand:在服務啟動的時候根據
pm.start_servers
指令生成程序,而非動態生成。 -
pm = static:子程序的數量是由
pm.max_children
指令來確定的。
檢視完整列表,深入瞭解 php-fpm.conf
的所有指令。
PHP-FPM 程序管理器(PM)和 CPUFreq Governor 的相似之處
現在,我們要說些偏離主題,但我覺得和 PHP-FPM 調優有關的事情。好了,我們都有過在某些時候的 CPU 緩慢問題,無論是膝上型電腦、VM 或者是專用的伺服器。還記得 CPU 頻率縮放問題嗎?(CPUFreq governor)這些設定在類 Unix 系統和 Windows 上是有效的,可以通過修改 CPU governor,將其從 ondemand
performance
來提高效能並加快系統的響應。現在,讓我們來比較下列 CPUFreq governor 描述和 PHP-FPM PM 有哪些相似之處:
- Governor = ondemand:根據當前負荷動態調整 CPU 頻率。先將 CPU 頻率調整至最大,然後隨著空閒時間的增加而縮小頻率。
-
Governor = conservative:根據當前負荷動態調整頻率。比設定成
ondemand
更加緩慢。 - Governor = performance:始終以最大頻率執行 CPU。
注意到相似之處了嗎?這就是我這個比較的首要目的,為了找到一個最好的方式來寫這篇文章,推薦你將 PHP-FPM 的 pm static
使用 CPU Governor 的 performance
設定是一個非常安全的效能提升方式,因為它能完美的使用你伺服器 CPU 的全部效能。唯一需要考慮的因素就是一些諸如散熱、電池壽命(膝上型電腦)和一些由 CPU 始終保持 100% 所帶來的一些副作用。一旦設定為 performance
,那麼它確實是你 CPU 最快的設定。相關例項請閱讀 'force_turbo' 在 Raspberry Pi 上的設定,它教你在 RPi 板上使用 performance
Governor,由於 CPU 時鐘速度較低,效能改善將更加明顯。
使用 pm static
優化你的伺服器效能
PHP-FPM 的 static
設定取決於你伺服器有多少閒置記憶體。大多數情況下,如果你伺服器的記憶體不足,那麼 PM 設定成 ondemand
或 dynamic
將是更好的選擇。但是,一旦你有可用的閒置記憶體,那麼把 PM 設定成 static
的最大值將減少許多 PHP 程序管理器(PM)所帶來的開銷。換句話說,你應該在沒有記憶體不足和快取壓力的情況下使用 pm.static
來設定 PHP-FPM 程序的最大數量。此外,也不能影響到 CUP 的使用和其他待處理的 PHP-FPM 操作。
在上面的截圖中,這臺伺服器的設定( pm = static
,pm.max_children =100
)最多使用了 10GB 的記憶體。請注意高亮的列。Google 分析圖中大概有 200 個活躍使用者(60秒內)。在這種使用者量下,有 70% 的 PHP-FPM 子程序被閒置。這意味著,無論當前流量如何,PHP-FPM 始終保持著足夠多的程序。閒置的程序始終保持線上,就算達到了流量的峰值也能快速響應,而不是等待 PM 生成子程序,然後在 x pm.process_idle_timeout
秒後將此程序結束。我將 pm.max_requests
設定的非常高,因為這是一個不可能發生記憶體洩漏的 PHP 生產伺服器。如果你對你的 PHP 指令碼有著 110% 的信心,那麼你可用選擇使用 pm.max_requests = 0
。但建議適當的重啟服務。將請求數量設定的很高,是為了避免過高的 PM 開銷。例如,設定 pm.max_requests = 1000
,但這需要根據 pm.max_children
的設定和實際每秒的請求數量來決定。
截圖使用 Linux top 通過 'u'(user)選項和 PHP-FPM 使用者名稱進行過濾。並只顯示了前 50 個左右(未統計)的程序,但基本上 top
命令也只會顯示適合你終端視窗大小的內容 —— 在本例中,使用 %CPU
排序。要檢視全部的 100 條 PHP-FPM 程序的話,你需要使用以下命令:
top -bn1 | grep php-fpm
何時使用 ondemand 和 dynamic
使用 pm dynamic
,您可能會出現類似於下面的錯誤:
WARNING: [pool xxxx] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 4 idle, and 59 total children
您可能會嘗試調整 pm 配置,但仍然會看到同樣的錯誤\在這種情況下,pm.min
太低,並且因為流量和峰值波動很大,使用 pm dynamic
可能難以調整
一般的建議是使用 pm ondemand
。 然而,情況會變的更糟,因為 ondemand
會在沒有流量時關閉空閒程序,然後最終會產生與流量波動很大一樣的開銷問題 (除非您設定空閒超時的時間非常非常的長)
但是,當您擁有多個 pm 程序池時,pm dynamic
, 特別是 ondemand
是可以為您節省時間的。例如在共享的 VPS 上,有 100+ 的 cPanel 賬號和 200+ 的域名,使用 pm.static
或者是 pm.dynamic
都是不可能的,即使在沒有任何流量的情況下,記憶體會被瞬間用完,而 pm.ondemand
意味著所有空閒的子程序都會被完全關閉,節省了大量記憶體。cPanel 的開發者已經意識到了這個問題,現在的 cPanel 預設就是設定為 pm.ondemand
。
結論
當流量波動比較大的時候,,PHP-FPM 的 ondemand
和 dynamic
會因為固有開銷而限制吞吐量。 您需要了解您的系統並設定 PHP-FPM 程序數,以匹配伺服器的最大容量。\從 pm.max_children
開始,根據 pm dynamic
或 ondemand
的最大使用情況去設定
您會注意到,在 pm static
模式下,因為您將所有內容都儲存在記憶體中,所以隨著時間的推移,流量峰值會對 CPU 造成比較小的峰值,並且您的伺服器負載和 CPU 平均值將變得更加平滑。 每個需要手動調整的 PHP-FPM 程序數的平均大小會有所不同
更新:附上一張 A/B 測試圖。