Linux

PHP5 到 PHP7 意外增加容器內的記憶體使用量

  • October 23, 2021

上週我們更新了幾個 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.x7.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_fileauto_append_file指令php.ini來執行它。

但是,該解決方案對我的情況沒有幫助,因此不能保證它會起作用。

由於目前沒有簡單的方法來改變這種行為,我找到了另一種解決記憶體問題的方法(它應該適用於 PHP7、PHP8):

  1. 而不是使用php-cgi,使用php-fpm
  2. 設置 FPM 配置以使用最少數量的子程序,但如果需要,讓它創建子程序,為此,您可以使用ondemandmode 或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 個客戶端

表中的值是近似值,僅用於說明目的(無論如何都不是真正的基準)。

引用自:https://serverfault.com/questions/1080635