中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

深入理(li)解 PHP-FPM 的(de)最佳配置

深入理解 PHP-FPM 的最佳配置

對大(da)多數開發(fa)者來說,PHP-FPM 的配(pei)置并不是日常工作中(zhong)需(xu)要(yao)深入研究的東(dong)西。這沒什么問(wen)題,畢竟(jing)不是每個人都想或需(xu)要(yao)在服務器調優上花(hua)時(shi)間(jian)。

況且,現在(zai)有很多托管服(fu)(fu)務(wu)(寶塔(ta), 1panel等(deng))可以(yi)幫(bang)你(ni)把(ba)服(fu)(fu)務(wu)器配(pei)(pei)置好,安裝所有依賴(包括 PHP-FPM),你(ni)只(zhi)需(xu)要在(zai)控制(zhi)面板點幾下(xia)就能部(bu)署代碼。也許你(ni)們公司有專門的運維,或者(zhe)有資深開發(fa)在(zai)負責這塊(kuai)。即便(bian)真要自(zi)己(ji)配(pei)(pei)置 PHP-FPM,多半也就是翻(fan)幾篇文章,改改參數(shu),或者(zhe)直(zhi)接用默認配(pei)(pei)置。這很正常——誰有那么多時間去鉆研每個服(fu)(fu)務(wu)器配(pei)(pei)置細節,尤其這只(zhi)是工作(zuo)的一小部(bu)分(fen)。

但隨著應用不(bu)斷迭代、用戶越來(lai)越多,你可(ke)能(neng)會發(fa)現(xian)服(fu)務(wu)器開始(shi)變慢,請求處理(li)時(shi)間越來(lai)越長,內(nei)存(cun)占用接近上限(xian),甚至服(fu)務(wu)器直接掛掉(diao)。

最近我的(de)一臺服務器就(jiu)遇到了類似(si)問題,所(suo)以(yi)我決定花(hua)點時(shi)間搞清(qing)楚(chu) PHP-FPM 到底(di)是怎么工作的(de),不同配置會帶來什么影(ying)響。我看了很多文章(zhang)、討論和評論,然(ran)后自己做了些測(ce)試(shi)來驗(yan)證。以(yi)下是我的(de)一些心得。

問題排查

如果問題(ti)確實出在 PHP-FPM 上(shang),有幾個排(pai)查方向。首先(xian)檢查 PHP-FPM 的(de)日志,重點關注 max children 相關的(de)警告(gao)。PHP-FPM 的(de)主(zhu)進(jin)程會(hui)按(an)需生成子進(jin)程,直到達到 max children 的(de)上(shang)限。每個子進(jin)程一次只能處理一個請求(比如對你應(ying)用的(de)一次訪問)。所以如果 max_children 設(she)置成 5,而同(tong)時有 10 個用戶在訪問應(ying)用,日志里很可能會(hui)出現(xian)這樣的(de)警告(gao):

WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

這會(hui)導致部分請求(qiu)被延(yan)遲(chi),直到有子(zi)進程空閑出(chu)來。可以(yi)用下面的命令檢(jian)查日志里有沒有這類警告。如(ru)果你用的是(shi) PHP-FPM 8.2:

sudo grep max_children /var/log/php8.2-fpm.log.1 /var/log/php8.2-fpm.log

注意你系(xi)統(tong)上的日志(zhi)路徑可(ke)能不(bu)(bu)同(tong),記得先確認。另外,除了(le)替換 PHP 版本號,有些系(xi)統(tong)的日志(zhi)文件(jian)名里不(bu)(bu)帶版本號,那就直接(jie)用(yong) php-fpm:

sudo grep max_children /var/log/php-fpm.log.1 /var/log/php-fpm.log

后(hou)面提到(dao)的(de)所有(you) php-fpm 命令都是(shi)(shi)同樣的(de)道(dao)理。我(wo)會用 php-fpm8.2 或 php8.2-fpm,因為這是(shi)(shi)我(wo)的(de)版(ban)本(ben),你的(de)可能(neng)是(shi)(shi) php-fpm7.4(php7.4-fpm)或者直接就(jiu)是(shi)(shi) php-fpm。

不(bu)想打開配置文(wen)件的話,可以用這個命令快(kuai)速(su)查看當前配置:

sudo php-fpm8.2 -tt

這樣(yang)就能找到 pm.max_children 這一行,確(que)認 max_children 是不(bu)是真的設置(zhi)成了 5:

[19-Mar-2024 22:48:10] NOTICE:  pm.max_children = 5

另外要關注的是服務器內存(cun)使用情況。用 htop 按內存(cun)排(pai)序,可以(yi)看到(dao)內存(cun)是不是快用完(wan)了(le),PHP-FPM 進程占了(le)多少。

這(zhe)可(ke)(ke)能是(shi) max_children 設置太高,生成的子進程太多(duo),服務器內(nei)存(cun)撐不住(zhu)了。或者,如果重啟 PHP-FPM 后內(nei)存(cun)使用量下降,然(ran)后又(you)慢慢漲回去,那多(duo)半是(shi)代碼有內(nei)存(cun)泄漏。理(li)想情(qing)況下當然(ran)要找到泄漏點并修復(fu),但定位內(nei)存(cun)泄漏有時候挺難的,尤其在大(da)項目里,而且(qie)泄漏可(ke)(ke)能來(lai)自某個必需的第三方庫。

第一個問題可以通(tong)過優化配置解(jie)決,內存泄漏的話 PHP-FPM 這邊也有些緩解(jie)辦法,稍后會(hui)講。

順便說一下(xia),重啟(qi) PHP-FPM 的(de)命令(ling)可能是(shi)這樣的(de)(但你的(de)情況可能不同,所以要確(que)認一下(xia)):

sudo service php8.2-fpm restart

如(ru)前面說的,重啟 PHP-FPM 能臨時緩解內存(cun)泄漏問題(但不是(shi)根本解決),給(gei)你(ni)爭取時間去修復(fu)泄漏或調(diao)整(zheng)配(pei)置。

配置進程管理器

現(xian)在(zai)可(ke)以(yi)開(kai)始(shi)修改 PHP-FPM 的配置文(wen)件了,看(kan)看(kan)怎(zen)么針對實際情況做優化。編(bian)輯(ji)主配置文(wen)件的命(ming)令:

sudo nano /etc/php/8.2/fpm/pool.d/www.conf

里面有各(ge)種配置項(xiang),我(wo)們只講(jiang)幾(ji)個(ge)(ge)對性能影響最(zui)大(da)(da)的。首先要(yao)決定進程管理器如何(he)控制子進程數量。有 3 個(ge)(ge)選項(xiang):static、dynamic 和(he) ondemand。大(da)(da)多數情況下默(mo)認是 dynamic。這幾(ji)個(ge)(ge)選項(xiang)有什(shen)么區別?假設你確(que)定服務器最(zui)多需要(yao) 10 個(ge)(ge)子進程:

static 會(hui)始終保持(chi)所有 10 個進(jin)(jin)程(cheng)運行,理論(lun)上最快,因為進(jin)(jin)程(cheng)都已經在那兒了,負(fu)載(zai)上來(lai)時不需要 fork 新進(jin)(jin)程(cheng)。但代價是即使沒人訪問網站,這 10 個進(jin)(jin)程(cheng)也會(hui)一(yi)直占著(zhu)內存。

dynamic 可以(yi)靈(ling)活調整;比如一開始啟動 3 個進程,負載(zai)上來時 fork 到最多(duo) 10 個,負載(zai)下去后減少到 6 個等待連(lian)接。這個選(xuan)項在內存占用和響(xiang)應(ying)速(su)度之間找平衡,至少理論上如此。

最后是 ondemand,一開(kai)始不(bu)(bu)生成(cheng)任何子(zi)進(jin)(jin)(jin)程,負載上(shang)來時最多(duo)創建(jian) 10 個,負載下去后可(ke)能又回到 0 個。這(zhe)個選項(理論(lun)上(shang))適合(he)流量不(bu)(bu)大的(de)中(zhong)小型應用、預發布環境(jing),或者多(duo)租戶共(gong)享服務器。由于子(zi)進(jin)(jin)(jin)程一直在回收,可(ke)以幫助(zhu)控制內存泄(xie)漏(lou),因為進(jin)(jin)(jin)程在內存累積之前(qian)就被干掉了。缺(que)點是需要頻(pin)繁(fan) fork 新進(jin)(jin)(jin)程,可(ke)能影響性能和響應速(su)度。

設置(zhi)這些選項(xiang)之前(qian),需要算(suan)出 PHP-FPM 進(jin)程(cheng)(cheng)(cheng)的最(zui)大負載。也(ye)就(jiu)是確定服務器(qi)能(neng)跑多少(shao)個(ge)子進(jin)程(cheng)(cheng)(cheng),然后(hou)設置(zhi) max_children 值。怎(zen)么算(suan)?這有(you)點(dian)麻煩,因為理想情況下(xia)要知道單(dan)個(ge)子進(jin)程(cheng)(cheng)(cheng)平均(jun)用(yong)多少(shao)內存(cun)。問題是多個(ge)進(jin)程(cheng)(cheng)(cheng)通常(chang)會共(gong)享一些內存(cun),所(suo)以很難精確算(suan)出單(dan)個(ge)進(jin)程(cheng)(cheng)(cheng)的實際內存(cun)使(shi)用(yong)量。

網上有(you)很多腳本和文章教你怎么算 PHP-FPM 進程的平(ping)均內存(cun)消耗,但大多數我試下(xia)來感覺不(bu)太對,算出(chu)來的值比(bi)預期高很多。

有(you)個 Python 腳本在好幾篇文章里(li)都(dou)提到了(le),看起來比較(jiao)靠譜。可以用這個命令算出每個程序(xu)的總內(nei)存使(shi)用量(liang):

cd ~ &&
wget //raw.githubusercontent.com/pixelb/ps_mem/master/ps_mem.py &&
chmod a+x ps_mem.py &&
sudo python3 ps_mem.py

注意我用的是(shi) python3,你的系(xi)統可(ke)能(neng)(neng)只需要 python。跑完腳本(ben)后,可(ke)能(neng)(neng)會(hui)看到類(lei)似這(zhe)樣(yang)的結果:

2.1 GiB + 127.5 MiB =   2.2 GiB       php-fpm8.2 (31)

這說(shuo)明 31 個 PHP-FPM 進(jin)程用了 2.2 GB 內存(cun),平均每個進(jin)程約 73 MB。另(ling)一個有用的命令可以查看空閑和(he)活(huo)動(dong)進(jin)程數:

sudo service php8.2-fpm status -l

看這一行就(jiu)能知道子進程(cheng)的當前狀(zhuang)態:

Status: "Processes active: 0, idle: 30, Requests: 56116, slow: 0, Traffic: 0req/sec"

這里沒(mei)有活動(dong)進(jin)程,30 個(ge)空閑進(jin)程,加上 1 個(ge)主進(jin)程,總(zong)共 31 個(ge),和 Python 腳本報的一致。

Python 腳本(ben)也會報總內存(cun)使(shi)用(yong)(yong)量。可以隨時跑 htop 或 free -hl 檢查服務器當前內存(cun)使(shi)用(yong)(yong)情況,看看這些數(shu)字(zi)是否(fou)合理、是否(fou)對得上。

還有一點(dian),如果真有內(nei)存(cun)泄漏,單個進程(cheng)的(de)(de)內(nei)存(cun)可能會漲到(dao) php.ini 里定義的(de)(de) memory_limit,默認一般是 128 MB。所以(yi)保守起見(jian),可以(yi)直接用這個值(zhi)作為單個進程(cheng)的(de)(de)平均值(zhi)。

好,現(xian)在(zai)可(ke)以(yi)算 max_children 值了。假設有臺 8 GB 內存的(de)服務器,其(qi)他程(cheng)序用(yong)(yong)了 2 GB,剩 6 GB。再留 1 GB 作為緩(huan)沖,防止意(yi)外情況(kuang)或者(zhe)未來應用(yong)(yong)增(zeng)長、新增(zeng)進(jin)程(cheng)什(shen)么的(de)。這樣就剩 5 GB 給 PHP-FPM。前(qian)面(mian)算出單(dan)個進(jin)程(cheng)用(yong)(yong)約 73 MB 內存,用(yong)(yong) 5 GB 除以(yi) 73 MB 就得到 max_children 值:

5120 (MB) / 73 (MB) = 70.14

所以(yi)這臺(tai)服務器(qi)的 max_children 應(ying)該設置(zhi)成 70。這樣無論選(xuan)哪(na)個(ge)進程(cheng)管理器(qi)(pm)選(xuan)項,PHP-FPM 最多都只會生成 70 個(ge)子進程(cheng)。

如果用 pm = static,就不需要設置(zhi)其他(ta)選項了。70 個子進程會立即生(sheng)成,隨(sui)時(shi)待(dai)命。但要記住(zhu)代價(jia):這(zhe)些(xie)進程會一直占著 5 GB 內存。

如果用 pm = ondemand,只需要考慮一個額外設置:pm.process_idle_timeout。由于 ondemand 模式下子進程(cheng)會不(bu)斷(duan)生成和終止,這個設(she)置告訴(su) PHP-FPM 什么時候干掉空(kong)閑的(de)子進程(cheng)。默認是 10 秒,需要的(de)話可以改,不(bu)過(guo)默認值已經(jing)挺合(he)理(li)了。

如果用 pm = dynamic,需要考慮幾個額外設置。pm.start_servers 是啟動或重啟 PHP-FPM 時立即生成的子進程數。pm.min_spare_servers 設置最小空閑子進程數。pm.max_spare_servers 決(jue)定最大空閑子(zi)進程數。

假設我們這樣設置:

pm = dynamic
pm.max_children = 70
pm.start_servers = 20
pm.min_spare_servers = 20
pm.max_spare_servers = 40

實際運行是(shi)這樣的。上面例子(zi)里 start_servers 設置為 20,PHP-FPM 一啟動就會生成(cheng) 20 個(ge)(ge)子(zi)進程(cheng)(cheng),占(zhan)用相(xiang)應的內存(cun)。有請(qing)(qing)求過來時,這 20 個(ge)(ge)進程(cheng)(cheng)中(zhong)的部分或(huo)全部會變成(cheng)活動狀態處理(li)請(qing)(qing)求。沒流量時,這 20 個(ge)(ge)進程(cheng)(cheng)會空(kong)閑等(deng)待;它(ta)們不會被終止,繼續占(zhan)著(zhu)內存(cun)。

把 min_spare_servers 設置(zhi)得比(bi)(bi) start_servers 低(di)(比(bi)(bi)如 15)沒什(shen)么意義,因為(wei) 20 個子進(jin)程(cheng)會立(li)即生成,即使空閑(xian),主進(jin)程(cheng)也(ye)不(bu)會為(wei)了(le)達到 15 的最小值(zhi)而終(zhong)止 5 個。而且 min_spare_servers 不(bu)能比(bi)(bi) start_servers 大,所以最好就把 min_spare_servers 設置(zhi)成和 start_servers 一樣(yang)。

如果大量請(qing)求涌入,20 個(ge)(ge)子(zi)進(jin)(jin)程(cheng)不夠用,主(zhu)進(jin)(jin)程(cheng)會生(sheng)成(cheng)額(e)外的(de)子(zi)進(jin)(jin)程(cheng),最多(duo)到 max_children 值,這里是(shi) 70。假(jia)設為了(le)(le)應對流(liu)量激增(zeng)生(sheng)成(cheng)了(le)(le) 70 個(ge)(ge)子(zi)進(jin)(jin)程(cheng)。過一會兒,流(liu)量恢(hui)復正(zheng)常,不再需要 70 個(ge)(ge)進(jin)(jin)程(cheng)了(le)(le),大部(bu)分或全部(bu)進(jin)(jin)程(cheng)變(bian)成(cheng)空(kong)閑(xian)。這時(shi)主(zhu)進(jin)(jin)程(cheng)會終(zhong)止(zhi)空(kong)閑(xian)子(zi)進(jin)(jin)程(cheng),直到 max_spare_servers 值,這里是(shi) 40。然(ran)后你就(jiu)剩 40 個(ge)(ge)空(kong)閑(xian)進(jin)(jin)程(cheng),它們(men)不會被進(jin)(jin)一步終(zhong)止(zhi),繼續占著內存。

所以(yi)(yi)設置這(zhe)(zhe)些值(zhi)時要(yao)記(ji)住:如果需(xu)要(yao)生成(cheng)比(bi) start_servers 更多的進(jin)(jin)程(cheng)(cheng)(cheng),流(liu)量高峰(feng)過(guo)后你會剩下那么多子(zi)進(jin)(jin)程(cheng)(cheng)(cheng)(最多到(dao) max_spare_servers 值(zhi))在(zai)(zai)運行。比(bi)如需(xu)要(yao)生成(cheng) 30 個(ge)子(zi)進(jin)(jin)程(cheng)(cheng)(cheng),你會剩 30 個(ge)在(zai)(zai)運行;需(xu)要(yao)生成(cheng) 50 個(ge),過(guo)一會兒會剩 40 個(ge)(因為(wei) max_spare_servers)在(zai)(zai)運行。所以(yi)(yi)如果不想最終可能有 40 個(ge)子(zi)進(jin)(jin)程(cheng)(cheng)(cheng)在(zai)(zai)后臺跑著(zhu),可以(yi)(yi)考慮(lv)降(jiang)低這(zhe)(zhe)個(ge)值(zhi),甚至讓它(ta)和 start_servers 一樣。這(zhe)(zhe)些情況會一直(zhi)保持到(dao)你重(zhong)啟(qi) PHP-FPM。重(zhong)啟(qi)后會根據 start_servers 重(zhong)新(xin)生成(cheng) 20 個(ge)子(zi)進(jin)(jin)程(cheng)(cheng)(cheng)。

很多(duo)文章里有個公式,建議(yi)根據 CPU 核心數來設置 start_servers、min_spare_servers 和 max_spare_servers 以獲得最佳性能:

pm.start_servers = CPU 核心數 x 4
pm.min_spare_servers = CPU 核心數 x 2
pm.max_spare_servers = CPU 核心數 x 4

這個公式(shi)據(ju)(ju)說(shuo)是基(ji)于單(dan)個 CPU 核(he)心能并(bing)(bing)發(fa)處理多少進(jin)程的某種假設。我不(bu)確定(ding)是誰開始這么搞的,這些(xie)乘(cheng)數怎(zen)么推(tui)導(dao)出來的,但有一(yi)點讓(rang)我覺得(de)(de)不(bu)對勁——把 min_spare_servers 設得(de)(de)比 start_servers 低,如我上(shang)面解(jie)釋的,會(hui)(hui)導(dao)致 min_spare_servers 值永遠用(yong)不(bu)上(shang)。而且(qie)在(zai)我的測試中(稍(shao)后會(hui)(hui)講),用(yong)這個方(fang)法并(bing)(bing)沒看到明顯(xian)的性(xing)能提升(sheng)。所以我覺得(de)(de)這個公式(shi)不(bu)該(gai)盲目照(zhao)搬,要根(gen)據(ju)(ju)實際情況調整。

關于 max_children 和 dynamic 相關設(she)置(zhi),最(zui)好的(de)(de)建議就是邊(bian)(bian)監控邊(bian)(bian)調優(you)。每種情況都不(bu)一樣——你的(de)(de)資(zi)源(yuan)、負載、整體策略都不(bu)同。按照上面的(de)(de)指導原則,從合理的(de)(de)值開(kai)始,隨著應用增長(chang)和變化,不(bu)斷調整配置(zhi)。

這一節還有個值得注意的選項:pm.max_requests。如果(guo)真有(you)內(nei)存泄漏,這個(ge)設置可以讓子進程在(zai)處理(li)一定數量請求后(hou)被回收。默認是 0,意(yi)味(wei)著進程不會因為這個(ge)選項被終(zhong)止。合理(li)的值可能是 500 或 1000 個(ge)請求,取決于你的場(chang)景(jing)。比如設置成 500,子進程處理(li)了 500 個(ge)請求后(hou)會被終(zhong)止(釋(shi)放累積的內(nei)存),然后(hou)重新生成。

實際測試

我決定做幾個性能(neng)測試來(lai)驗證理論(lun):static 處理請(qing)求應(ying)該最快,因為不需要(yao)臨時(shi) fork 子(zi)進程(cheng);dynamic 應(ying)該居(ju)中,因為部分進程(cheng)已經在跑,部分需要(yao)按需 fork;ondemand 應(ying)該最慢(man),因為它不停地(di)生成和(he)終止進程(cheng)。結果如下。

我用 ApacheBench 做測試,按照(zhao)建議從(cong)另一(yi)臺服務(wu)器(qi)(qi)發送請求,不是(shi)從(cong)被(bei)測服務(wu)器(qi)(qi)本(ben)身(shen)發的(de)(de)。被(bei)測服務(wu)器(qi)(qi)有(you) 16 GB 內(nei)存和 4 個 CPU 核心,PHP-FPM 配合 NGINX,請求走 Laravel 應(ying)用。所有(you)測試用例(li)的(de)(de) max_children 都是(shi) 80。我比較的(de)(de)是(shi) 90% 請求的(de)(de)響應(ying)時間。下(xia)面表(biao)格里只列出不同 pm 選項之(zhi)間的(de)(de)毫秒差(cha)異,0ms 是(shi)最快的(de)(de)。

測試命令示例:

ab -n 1000 -c 10 //example.com

這個例子會發送 1000 個請求,并發級別(bie)是每次 10 個。

先(xian)看(kan)第(di)一個測試。我想看(kan)看(kan)明顯達到 max_children 限制(zhi)時(shi),不同 pm 選項如何影響(xiang)響(xiang)應時(shi)間。所以發了 25000 個請求,并發級(ji)別 1000。

用(yong) dynamic 時的(de)額外值如下(后面簡稱 20/20/40):

pm.start_servers = 20
pm.min_spare_servers = 20
pm.max_spare_servers = 40

結果如下:

Static Dynamic On demand
+1223ms +845ms 0ms

結(jie)果顯示,理(li)論(lun)上應該最慢(man)的 ondemand 實(shi)際上最快,而 static 出(chu)人意料地(di)最慢(man),比 ondemand 慢(man)了(le)一秒多。

第(di)二個測(ce)試(shi)發(fa)了 10000 個請求,并發(fa)級別 100。測(ce)試(shi)了兩種(zhong) dynamic 設(she)置,一種(zhong)是(shi)第(di)一個測(ce)試(shi)的(20/20/40),另一種(zhong)用基(ji)于 CPU 核心的公(gong)式(16/8/16):

Static Dynamic (20/20/40) Dynamic (16/8/16) On demand
0ms +14ms +2ms +24ms

這次 static 最快(kuai),基于公式的 dynamic 緊隨其(qi)后(hou),ondemand 最慢,符合(he)理論預期。但(dan)總的來說,對大(da)多數(shu)網站而言(yan),+24ms 算不上(shang)什么性能提升(sheng),不同(tong)選項之間差異不大(da)。

最后一個測試(shi)只(zhi)發了(le) 2000 個請求,并(bing)發級別 16。同樣(yang)用(yong)了(le)兩種 dynamic 設置(zhi)(20/20/40 和 16/8/16):

Static Dynamic (20/20/40) Dynamic (16/8/16) On demand
+2ms +7ms +10ms 0ms

這(zhe)個規模下 ondemand 再次獲勝(sheng),static 緊隨其后(hou),基于公式的 dynamic 墊底。這(zhe)次差異(yi)更小了,第一(yi)(yi)名(ming)和(he)最(zui)后(hou)一(yi)(yi)名(ming)之間(jian)只(zhi)差 10ms。

最(zui)終得到了一些(xie)(xie)意外結果。測試(shi)表明,當并(bing)發(fa)請求數(shu)量遠超 max_children 值(zhi),或者遠低于 max_children 值(zhi)時,ondemand 是最(zui)佳選擇。當并(bing)發(fa)請求數(shu)量接近 max_children 值(zhi)時,static 最(zui)佳。但(dan)要注意,第二個測試(shi),特(te)別是第三個測試(shi)中,響應時間差異相當小。而且(qie)如(ru)果重新(xin)跑這些(xie)(xie)測試(shi),排名很(hen)可能會變(bian)。

所以(yi)這些結(jie)果不(bu)(bu)能當成鐵(tie)律,理論也(ye)是(shi)如此。我覺得在(zai)現代服務器上,fork 一個(ge)新子(zi)進程已(yi)經(jing)不(bu)(bu)是(shi)什么(me)(me)昂(ang)貴(gui)操(cao)作(zuo)了,不(bu)(bu)會明(ming)顯(xian)影(ying)響(xiang)響(xiang)應時間(jian),至(zhi)少在(zai)測試(shi)的(de)規模上不(bu)(bu)會。這就是(shi)為(wei)什么(me)(me) ondemand 不(bu)(bu)該被輕易(yi)否定,即使在(zai)處理請求速度(du)方(fang)面(mian)也(ye)是(shi)如此。

最(zui)好(hao)的(de)(de)前進方式是(shi)做(zuo)你自己的(de)(de)測(ce)(ce)試,因為你的(de)(de)負載、設置和每個(ge)請求執行(xing)的(de)(de)操作可能完(wan)全不同,然后根據這些(xie)測(ce)(ce)試,應用看起來(lai)最(zui)高效的(de)(de)設置。

其他設置

還有幾個(ge)額外的設置我們應該了解(jie)一下,在 PHP-FPM 出問題或者(zhe)你需要追蹤慢請求(qiu)時可(ke)能會(hui)很有用。

要啟用(yong) slowlog(當(dang)然是用(yong)來記錄慢請求的),我們需要編輯(ji)之前的同一個(ge)配置文件(jian):

sudo nano /etc/php/8.2/fpm/pool.d/www.conf

然后找(zhao)到 slowlog 部分:

slowlog = /var/log/php8.2-fpm.log.slow

取消注釋。那里還有幾個相關選項你應該考慮取消注釋。第一個是 request_slowlog_timeout,默認設置為 5 秒。如果你只想記錄耗時 3 秒及以上的請求,應該取消注釋并修改這個值。第二個是 request_slowlog_trace_depth,默認(ren)(ren)設置為 20。在 Laravel 應(ying)用(yong)中,這(zhe)個值可能太低,無法遍歷所有(you) vendor 函數并到達實際被調(diao)用(yong)的(de)代碼(ma),比如你的(de) controller。所以(yi)我認(ren)(ren)為大(da)多數情況下(xia),50 應(ying)該沒問題,但要(yao)確認(ren)(ren)一(yi)下(xia)是否適合你。

最終整個 slowlog 設置可能(neng)是這樣的:

slowlog = /var/log/php8.2-fpm.log.slow
request_slowlog_timeout = 3s
request_slowlog_trace_depth = 50

最后,還有另一個(ge)配置文(wen)件我們(men)可以(yi)編(bian)輯(ji),控制當子(zi)進程因為某種(zhong)原因開始失敗時會(hui)發生什么。下面是編(bian)輯(ji)這個(ge)文(wen)件的示例(li):

sudo nano /etc/php/8.2/fpm/php-fpm.conf

在那個文件(jian)中,我(wo)們關注 3 個相互關聯的選(xuan)項,它們默認都設(she)置(zhi)為 0 并(bing)被(bei)注釋掉。如(ru)果你(ni)打(da)算使用它們,確(que)保先取(qu)消注釋。之后(hou),你(ni)可以把它們設(she)置(zhi)為這些值:

emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s

使(shi)用的值(zhi)是你(ni)可能在(zai)(zai)其他一些文章中(zhong)也(ye)會(hui)看(kan)到(dao)的。前兩個設置告訴 PHP-FPM,如果(guo)(guo)在(zai)(zai)一分(fen)鐘內(nei)有(you) 10 個子進程失(shi)敗,PHP-FPM 應該自動重(zhong)啟(qi)。第三個設置意味著(zhu)子進程在(zai)(zai)響應主(zhu)進程發送的信號(hao)之前會(hui)等待 10 秒。所以(yi)(yi)如果(guo)(guo)主(zhu)進程向子進程發送 KILL 信號(hao),它會(hui)有(you) 10 秒時間完成任(ren)務后再退(tui)出。當然,你(ni)可以(yi)(yi)根據需要(yao)調(diao)整(zheng)這些值(zhi)。

在失敗(bai)時(shi)重(zhong)啟 PHP-FPM 可能會(hui)解決一(yi)些問(wen)題,但如果問(wen)題與即使 PHP-FPM 重(zhong)啟后仍會(hui)重(zhong)現(xian)的東西有關,它(ta)會(hui)一(yi)直重(zhong)啟,直到你弄清楚到底發生(sheng)了什么。所(suo)以你應該自己決定,當發生(sheng)意(yi)外(wai)情況時(shi),是想讓 PHP-FPM 完(wan)全(quan)失敗(bai),還是讓它(ta)自動重(zhong)啟。

總結

本人(ren)討(tao)論了 max_children 選項的(de)最佳(jia)值。探討(tao)了不(bu)同進(jin)程管(guan)理器設(she)置的(de)優(you)勢(shi)和(he)缺陷,以及如(ru)何(he)測試它們。還了解了一些在(zai)調試慢請求或處理失敗時可能(neng)有(you)(you)用的(de)額外設(she)置。希望這篇(pian)文章對你(ni)(ni)有(you)(you)幫(bang)助(zhu),你(ni)(ni)能(neng)夠用文章中的(de)信(xin)息作(zuo)為(wei)起點(dian),更好(hao)地監控(kong)和(he)調優(you)你(ni)(ni)服務器上的(de) PHP-FPM。

posted @ 2025-10-17 07:54  JaguarJack  閱讀(177)  評論(0)    收藏  舉報