PHP 效能優化:記一次伺服器效能排查
背景:公司最近在 APP 上推廣一系列活動。其中有兩個活動:簽到 + 紅包雨。紅包雨屬於整點搶。使用者參與紅包雨活動前後會參與簽到活動。這樣就造成每天 10 點 Web 伺服器壓力很大。突然,有一天伺服器 TCP 連線數直接飆升超過了 PHP-FPM 能響應的數量。導致 APP 響應異常緩慢。於是就有了本文排查效能的記實。
思路一:檢視請求數量
我的第一反應是檢視整點時的 API 請求數量。通過日誌統計,請求數量很大,但是在伺服器承受範圍內。換句話說,伺服器處理這些請求綽綽有餘。因為,我們有 9 臺伺服器。每臺伺服器配置如下:
CPU:16核。 記憶體:16 GB 硬碟:SSD。 PHP-FPM 程序數:400
均衡負載採用的是阿里雲的 SLB。
資料庫採用了阿里雲的 RDS 高配版。檢視其負載也屬於低消狀態。
根據理論值,我們 9 臺伺服器最少能承受的請求數量等於:9 * 400 = 3200。
當然要達到這個併發數量級別,有可能資料庫會出現效能問題。
思路二:檢視 SQL/">MySQL 慢查詢日誌
通過對 MySQL 慢查詢日誌進行分析,幾乎沒有出現。或者說,出現的 MySQL 慢查詢日誌跟平常的差不多。都屬於一些管理後臺複雜查詢類別的慢查詢。
如思路一中所說:MySQL 伺服器負載很小。所以,排除了 MySQL 伺服器的問題。
思路三:檢視 PHP-FPM 慢請求
對 PHP-FPM 熟悉的同學,都應該知道在 PHP-FPM 配置檔案當中有如下兩個配置:
request_slowlog_timeout = 1 slowlog = log/slow.log
request_slowlog_timeout
的作用是告訴 PHP-FPM,凡是請到開始到響應結束之間消耗的時間超過 1 秒就認為慢請求。就將造成慢請求的日誌記錄在slowlog
指定的檔案當中。
結果,通過這個日誌我們發現了大量的慢請求。慢請求的關鍵日誌如下:
[27-Nov-2018 14:50:48][pool www] pid 19708 script_filename = xxxxxxx/public/index.php [0x00007fb12cc48688] file_put_contents() xxxxxxx/library/winer/Log.php:98 [0x00007fb12cc48138] store() xxxxxxx/apps/controllers/Index.php:54 [0x00007fff0b8f8780] indexAction() unknown:0 [0x00007fb12cc47998] run() xxxxxxx/public/index.php:13
上面的資訊我隱去了與環境相關的路徑字首。通過慢請求日誌可以看出,我們在呼叫file_put_contents
位置造成了慢請求的產生。這個位置是我們寫日誌造成的。
奇怪的是。我們寫日誌使用了阿里雲的雲盤。根據購買雲盤的配置為 5000 IOPS/s。也不會出現瓶頸。於是,我查看了我們這個位置的 PHP 程式碼。
file_put_contents($logPath, $logCtx, FILE_APPEND|LOCK_EX);
可以看到,我們加了一個LOCK_EX
引數。就是說寫入日誌的時候排它性,獨佔寫鎖。之所以當初要增加這個,是因為併發寫的時候會造成日誌位置錯亂,兩次日誌資訊互相包含。導致不能按照完整的順序寫入。
於是,我暫時把這個引數去掉之後,發現伺服器 TCP 連線數瞬間下降到合理水平。基本可以確定是這裡的問題了。於是,我把寫日誌更改為了非同步。在非同步裡面進行獨佔寫。
以上就是我排查本次問題的思路步驟。謝謝!