高併發下的php.int及PHP-fpm設定

程式設計師的貓發表於2021-02-09

Opcache 的執行流程大致如下,

E390.png

Opcache 的目地是避免重複編譯,減少 CPU 和記憶體開銷。

由於這篇文章的本意是想記錄以及備註一下開啟 opcache 後出現的一些問題,所以這篇文章不會記錄如何安裝 opcache 以及如何配置,推薦這篇文章大家參考一下就可以了,配置說的都很明確了。

正文

在配置中有 2 個配置很重要,需要重點關注

opcache.validate_timestamps=0;
opcache.revalidate_freq=60;

validate_timestamps 用於驗證是否要重新生成快取指令碼, 如果設定為 0(效能最佳),需要手動在每次 PHP 程式碼更改後手動清除 OPcache。 如果此值為 0,那麼 revalidate_freq 將失去作用。

revalidate_freq 用於控制 opcache 多久生成一次快取位元組碼,預設 60s。所以一般我們在開發環境中將上面兩個值配置為

opcache.validate_timestamps=1;
opcache.revalidate_freq=1;

或者乾脆直接關閉 opcache。

上面提到了,如果將 validate_timestamps 配置為 0 以後,我們每次部署 PHP 的時候預設是不會自動生成快取。這句話其是是不嚴謹的,因為部署 PHP 的時候有兩種方式,一種是直接覆蓋就檔案,另一種是使用 CI 釋出會自動生成新的部署目錄,並通過軟連線的方式指定到 web 目錄

如果是第一種部署方式的話,opcache 確實不會自動生成快取,因為 opcache 通過檔案的真實路徑進行快取,如果檔案存在就不會再次快取,也就導致了部署後線上並沒有看到新的功能程式碼。

而另一種方式的確會主動生成快取,因為上面說了,opcache 是通過檔案的真實路徑進行快取的,這就導致了每次部署都會生成快取位元組碼,那麼就導致了舊的快取沒有被清理,那麼遲早有一天會撐爆記憶體。

所以,在部署程式碼的時候如何清理 opcahce 生成的快取就成為了關鍵所在。

解決方案

通過搜尋實踐發現了幾種方式,分別為

  1. 平滑重啟 php-fpm
  2. 通過 opcache_reset () 函式
  3. 第三方庫

平滑重啟的方式就類似下面這樣,通過部署鉤子實現

cd /www/myproject
sudo -u www git reset --hard
sudo -u www git pull origin master
sudo -u root /etc/init.d/php-fpm-73 reload

使用 opcache_reset () 函式需要注意的問題就是在 cli 命令列下執行此函式並不能清理 php-fpm 下生成的快取位元組碼,所以可以通過一種曲線救國的方式

curl http://example.com/op.php

這個 op.php 檔案裡面就專門執行 opcache_reset () 函式,但是這種方式總感覺有點怪怪的。

通過第三方庫 (推薦) 的方式,大佬推薦 cachetool

伺服器中找到php-fpm.conf配置(有的會在引入的www.conf中)

[global]
pid = /usr/local/php/var/run/php-fpm.pid
error_log = /usr/local/php/var/log/php-fpm.log
log_level = notice

[www]
listen = /tmp/php-cgi.sock
listen.backlog = -1
listen.allowed_clients = 127.0.0.1
listen.owner = www
listen.group = www
listen.mode = 0666
user = www
group = www
pm = static
pm.max_children = 200
pm.start_servers = 40
pm.min_spare_servers = 10
pm.max_spare_servers = 20
pm.max_requests=1000
request_terminate_timeout = 100
request_slowlog_timeout = 0
slowlog = var/log/slow.log
一. pm= static

首先說一下pm這個值 pm = dynamic 這個是php的程式數是動態的 會根據訪問量來確定來回增加

而在高負載的php環境下我推薦設定 pm= static php-fpm程式數固定

二. pm.max_children=???

當用靜態模式下 程式數確定根據 pm.max_children來進進行確定 那麼問題來了我的伺服器應該設定多少php-fpm呢 ?

從理論的角度上說php-fpm程式數越多越好,相當於一個酒店有很多個充足的服務員來為你服務肯定會比較爽啊 ,你也不需要等待。

 但是。。。。現實上總是殘酷的   php-fpm的程式數會受到你的記憶體大小的限制。一般情況下我們    程式數 =用機器記憶體(M)除以2  再除以20(M);

 當然這個也不是絕對的   你需要知道:

你可以分配給php多大記憶體 :你的伺服器上是不是單純的php伺服器 有沒有比較耗費記憶體的其他程式(mysql)。
你的每個php-fpm記憶體佔多大 :記憶體佔用多大要根據你的php程式碼質量和處理的相關業務。當然你可以用命令去統計你的php-fpm平均佔用記憶體大小。
有人會問我如果設定不恰當會有什麼狀況出現呢?

   當數值偏小時請求到nginx會無法分配到php-fpm程式 導致502錯誤

  當數值偏大如果沒有大訪問量還好 如果訪問量較大的話 記憶體都會被php佔光了。導致系統響應緩慢 cpu-system 升高 系統不斷的去調整記憶體分配

      嚴重時會導致較高的 cup-wait 較高   記憶體不夠用了  直接寫磁碟  磁碟io直線增加 。cpu使用率也開始爆滿。(如圖所示)

三.request_terminate_timeout

  計算方式如下:如果你的伺服器效能足夠好,且寬頻資源足夠充足,PHP指令碼沒有迴圈或BUG的話你可以直接將”request_terminate_timeout”設 置成0s。0s的含義是讓PHP-CGI一直執行下去而沒有時間限制。

   而如果你做不到這一點,也就是說你的PHP-CGI可能出現某個BUG,或者你的寬頻不夠充足或者其他的原因導致你的PHP-CGI能夠假死那麼就建議你給”request_terminate_timeout”賦一個值,這個值可以根 據你伺服器的效能進行設定。

一般來說效能越好你可以設定越高,20分鐘-30分鐘都可以。由於我的伺服器PHP指令碼需要長時間執行,有的可能會超過10分鐘因此我設定了900秒,這樣不會導致PHP-CGI死掉而出現502 Bad gateway這個錯誤。

四.pm.max_requests
這個引數的含義是php-fpm工作程式處理完多少請求後自動重啟,主要目的就是為了控制請求處理過程中的記憶體溢位,使得記憶體佔用在一個可接受的範圍內。比較適用於伺服器搭載專案比較雜亂,有點請求會比較佔用記憶體

    導致php-fpm佔用比較大。在經過一定次數請求後會結束掉程式,釋放自己的記憶體。如果這個值太小就會導致所有的工作程式幾乎同時達到這個值並且進入需要重啟的狀態,當所有的工作程式都在同一時刻重啟就會發生在

  數秒內甚至更長的時間PHP將停止響應直到所有的程式均重啟完為止。這是不能接受的,所以我一般會把這個值設定為PHP啟動後第一批工作程式達到此值需要重啟時,第一個程式重啟與最後一個程式重啟之間的時間相差

  1分鐘以上,一般在壓力比較大的晚上這個差值將會擴大到5分鐘左右,此時對程式重啟對伺服器的負面影響就可以忽略了。

  下面補充幾個命令統計相關php-fpm 相關資料

1、檢視php-fpm的程式個數

ps -ef |grep “php-fpm”|grep “pool”|wc -l
2、檢視每個php-fpm佔用的記憶體大小

ps -ylC php-fpm –sort:rss
3.檢視PHP-FPM在你的機器上的平均記憶體佔用

ps –no-headers -o “rss,cmd” -C php-fpm | awk ‘{ sum+=$1 } END { printf (“%d%s\n”, sum/NR/1024,”M”) }’
4.檢視單個php-fpm程式消耗記憶體的明細

pmap $(pgrep php-fpm) | less

本作品採用《CC 協議》,轉載必須註明作者和本文連結
你還差得遠吶!

相關文章