PHP5 到 PHP7 意外增加容器內的記憶體使用量
上週我們更新了幾個 wordpress 站點,這些站點通過 LXD 將 Alpine Linux 作為主機(Ubuntu 20.04)中的容器執行。
更新摘要如下:
Alpine Linux v3.8 -> 3.14 PHP 5.3.6 -> 7.4.24 Wordpress 5.0.3 -> 5.7.3
問題
在這些更新之後,我們開始遇到伺服器性能問題,我們發現更新後的容器使用的記憶體(常駐記憶體)是舊容器的 3 倍或更多(大約 150MB 對 50MB),這導致伺服器開始更頻繁地交換。
在舊版本中(使用 PHP 5.3),
php
(程序)使用的記憶體會隨著頁面的處理(如預期的那樣)增加,但在它完成後,它會恢復正常。換句話說,類似於:10MB
—>95MB
—>10MB
。在更新的容器中,所使用的記憶體
php
以相同的方式增加,但不會恢復到“正常”:10MB
—>95MB
—>95MB
。每次使用新程序時,都會發生同樣的情況,通過可用子程序的數量(在本例中為每個站點 4 個)增加記憶體使用量。我試過的
- 將 PHP 版本降級到
7.2.x
和7.3.x
:同樣的事情- 更新為
php 8.0.11
:同樣的問題- 使用
apache2
而不是lighttpd
(目前 php 作為 fcgi 執行):相同的行為- 僅更新 Alpine 和 PHP 以確定 Wordpress 是否可能是原因:wordpress 不是原因
- 在沒有外掛的情況下執行 wordpress(以了解某些外掛是否可能導致問題):沒有變化
- 執行了一個簡單的連接循環(純 php):同樣的事情
- 在具有不同 wordpress 站點的不同伺服器中測試:相同的行為
它沒有恢復記憶體的原因是什麼?如何修復?
更新
- 我設置了一個乾淨的
Alpine 3.14
容器並執行了“簡單循環”測試。在這種情況下,常駐記憶體按預期減少了。但是,一旦我使用實際的 wordpress 站點進行測試,問題仍然存在。- 我設置了一個乾淨的
Ubuntu 20.04
容器並進行了相同的測試。結果與 clean 相同Alpine 3.14
。
根據這個錯誤報告,它並不是真正的錯誤,而是Zend 引擎記憶體管理下 PHP7+ 中的一個功能:
cmb@php.net :這是預期的行為。在請求關閉時,Zend 記憶體管理器不會釋放所有分配的塊,而是保留一些
$$ 1 $$以避免需要為下一個請求重新分配它們。
建議的解決方案是呼叫:gc_mem_caches()。如果需要,您可以使用
auto_prepend_file
和auto_append_file
指令php.ini
來執行它。但是,該解決方案對我的情況沒有幫助,因此不能保證它會起作用。
由於目前沒有簡單的方法來改變這種行為,我找到了另一種解決記憶體問題的方法(它應該適用於 PHP7、PHP8):
- 而不是使用
php-cgi
,使用php-fpm
- 設置 FPM 配置以使用最少數量的子程序,但如果需要,讓它創建子程序,為此,您可以使用
ondemand
mode 或dynamic
:
/etc/php7/php-fpm.d/www.conf
:pm = ondemand ; Adjust as needed: pm.max_children = 10
或者:
pm = dynamic ; Adjust as needed: pm.max_children = 10 pm.start_servers = 1 pm.min_spare_servers = 1 pm.max_spare_servers = 1
它們之間的主要區別是
ondemand
空閒時會使用更少的記憶體,但客戶端連接時會更慢。這是我的結果的比較:
- Max Load Time 測試同時執行 50 個客戶端
表中的值是近似值,僅用於說明目的(無論如何都不是真正的基準)。