Apache-2.2

儘管增加了 PHP 記憶體限制並確認沒有 RLimitMEM,但 Wordpress 網站重複出現 PHP 記憶體不足錯誤

  • June 12, 2018

幾乎每 4 分鐘,我就會在 php 錯誤日誌中看到以下記憶體不足錯誤:

01-Jul-2014 21:50:03 UTC] PHP Fatal error:  Allowed memory size of 268435456 bytes
exhausted (tried to allocate 72 bytes) in /home/[sitename]/public_html/wp-includes
/wp-db.php on line 1938

錯誤消息似乎支持 php.ini 的 memory_limit = 256M 設置被 PHP 認為是正確的。但是,我在 wordpress 中使用了幾個記憶體監控外掛,它們都報告說該站點在穩定狀態下使用了大約 35MB 的 RAM,並且在 OOME 發生之前它似乎根本沒有增長。記憶以前被設置在較低的水平,並在沒有解決症狀的情況下反復增加。幾乎總是正好 4 分鐘。有時正好是 3 分鐘或 3 分鐘 30 秒等。我安裝了一個 wordpress cron 外掛,以查看是否有計劃以 4 分鐘的間隔執行,但似乎沒有。

我檢查了 httpd.conf 文件並確認沒有 RLimitMEM 設置。我還通過 apachectl -V 確認我正在查看正確的 httpd.conf 文件。Top 說系統有半 GB 的可用 RAM。我發現訪問日誌中的條目與 php 錯誤日誌中的 OOME 之間沒有關聯。

該伺服器託管著相當多的站點。我不管理伺服器,但我一直在幫助解決相關站點上的一些問題。

對於如何繼續解決此問題的任何建議,我將不勝感激。

我終於想通了。

問題是站點上安裝的兩個外掛之間的衝突(特別是兩個外掛的配置方式)。 iThemes 安全外掛 ( http://ithemes.com/security ) 被配置為定期進行站點備份。進行數據庫備份的程式碼會轉儲數據庫中的每個表,並假設每個表的內容都可以完全放入記憶體中。與此無關,網站上安裝了另一個外掛,名為 Redirection ( http://urbangiraffe.com/plugins/redirection/) 用於維護重定向。該外掛具有記錄重定向和 404 響應的配置選項。不幸的是,這些日誌被設置為永不過期,並且針對我們網站的殭屍網路流量的 b/c 累積了近 90,000 條重定向日誌和 30,000 404 條日誌。由於 iThemes Security 外掛在嘗試創建備份時嘗試將整個表載入到記憶體中,因此 wp_redirection_logs 表消耗了 php 中的所有可用記憶體並導致程序崩潰。我懷疑 iThemes Security 試圖在每個可用的機會重新執行失敗的備份,導致每 3-4 分鐘出現一次錯誤。

我通過將重定向日誌設置更改為在 5 天后使重定向條目過期並且根本不記錄 404 錯誤來解決此問題。然後我不得不反复刷新日誌頁面以刪除過期條目。不再發生記憶體不足錯誤。

$$ edit $$從那以後,我從其他 wordpress 人那裡聽說過 iThemse Security 外掛在各種 wordpress 表上執行 SELECT * 時遇到了類似的錯誤。以下是我如何調試此問題的說明,以防您的問題相似但不完全相同: 在正常修復(增加 php 記憶體並確保實際工作,確認我的記憶體使用量隨著時間的推移穩定且低)之後,我對錯誤進行故障排除的方法是向 wp-db.php 添加一些調試日誌語句,所以我可以看到發生錯誤時發生了什麼。這是我為幫助縮小問題範圍所做的程式碼更改(請務必在嘗試此操作之前備份 wp-db.php,以便您可以輕鬆恢復設置,以防在編輯文件時出現問題):

function get_results( $query = null, $output = OBJECT ) {
   $this->func_call = "\$db->get_results(\"$query\", $output)";

   if ( $query )
       $this->query( $query );
   else
       return null;

   $new_array = array();
   if ( $output == OBJECT ) {
       // Return an integer-keyed array of row objects
       return $this->last_result;
   } elseif ( $output == OBJECT_K ) {
       // Return an array of row objects with keys from column 1
       // (Duplicates are discarded)
       foreach ( $this->last_result as $row ) {
           $var_by_ref = get_object_vars( $row );
           $key = array_shift( $var_by_ref );
           if ( ! isset( $new_array[ $key ] ) )
               $new_array[ $key ] = $row;
       }
       return $new_array;
   } elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
       // Return an integer-keyed array of...
       if ( $this->last_result ) {
           $emited = false;
           foreach( (array) $this->last_result as $row ) {
               if ( $output == ARRAY_N ) {
                   // ...integer-keyed row arrays
                   if (!$emitted) {
                       error_log("Current Mem: " . memory_get_usage() . ", eak mem: " . memory_get_peak_usage());
                       error_log($query);
                       $emitted = true;
                   }
                   $new_array[] = array_values( get_object_vars( $row ) );
               } else {
                   // ...column name-keyed row arrays
                   $new_array[] = get_object_vars( $row );
               }
           }
       }
       return $new_array;
   } elseif ( strtoupper( $output ) === OBJECT ) {
       // Back compat for OBJECT being previously case insensitive.
       return $this->last_result;
   }
   return null;
}

這是 6 行添加的程式碼;第一個將 $emitted 變數分配給 false 以跟踪我們是否已經記錄了此請求,然後將 5 行 if 子句實際記錄。

它的作用是在我們開始將查詢結果讀入記憶體之前列印出 php 消耗的目前記憶體和峰值記憶體,並列印出已執行的查詢。在我們開始閱讀結果之前,記憶體將使您了解您是否有合理的可用記憶體。如果可用記憶體接近您的限制(在幾 MB 以內),那麼問題可能出在其他地方,並且您實際上沒有足夠的空間來執行合理大小的查詢。如果像我一樣,在執行查詢之前您有大量可用記憶體,那麼請查看在記憶體不足之前執行的查詢是什麼(我的日誌條目都在 php 錯誤日誌中,但如果您的日誌被拆分跨和 iThemes 日誌和 php 錯誤日誌,根據時間戳在兩者之間關聯。

就我而言,這是一個 SELECT * FROM wp_redirection_logs;。該表已經失控 b/c 重定向外掛在我的站點上被錯誤配置為永不過期日誌條目。通過閱讀 iThemes 安全外掛的程式碼,很明顯,備份操作對數據庫中以 wp_ 前綴開頭的每個表執行 SELECT * FROM 查詢(如果您的站點配置為使用不同的前綴,則為其他前綴)站點或其他東西。)iThemes 安全性的其他區域(如 404 錯誤日誌)似乎也對可能超出可用記憶體的表發出 SELECT * 查詢。一旦你找到查詢是什麼,你就可以開始推理你的錯誤的原因,也許像我一樣修剪不必要的數據庫內容來解決這個問題。

如果您完成這些步驟並進行報告,我很樂意提供建議。

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