Linux OOM 排查實務:如何解決 Apache 記憶體耗盡導致的 WordPress 當機?

重點摘要 (Executive Summary)

  • 現象: 伺服器無預警變慢、SSH 卡頓、特定服務(如 Apache/MySQL)反覆崩潰重啟。
  • 主因: 通常並非外部攻擊,而是 Linux 核心觸發 OOM (Out of Memory) Killer 機制。
  • 關鍵解法:
    1. 透過 Log 確認 OOM 事件。
    2. 計算單一 Apache Process 的記憶體消耗。
    3. 依據物理記憶體上限,精算並調校 MaxRequestWorkers 參數。
    4. 長期建議從 MPM Prefork 遷移至 Event 模式。

當 Linux 主機發生 OOM (Out Of Memory) 時,最常見的症狀是整機回應延遲、Swap 分區瞬間飽和,緊接著某些關鍵服務(例如 Apache httpd 或 MySQL)被系統強制終止。

許多工程師在第一時間會誤判為 DDoS 攻擊,但實際上,這往往是伺服器資源配置不當所致。本文將整理一套標準的實務排查流程(SOP),並以 Apache 為例,深入探討如何進行合理的容量規劃 (Capacity Planning)。

一、 現場鑑識:確認「真的」是 OOM

在懷疑記憶體不足之前,我們必須先從系統日誌中尋找確鑿的證據。

1. 檢查核心日誌 (Kernel Log)

使用以下指令搜尋系統日誌,尋找核心殺手 (Kernel Killer) 的蹤跡:

# 檢查系統訊息
grep -i "Out of memory" /var/log/messages
# 或者使用 dmesg
dmesg | grep -i "killed process"

如果您看到類似下方的輸出,則確認是 OOM 無誤:

Out of memory: Kill process 2345 (httpd) score 950 or sacrifice child
Killed process 2345 (httpd) total-vm:40860kB, anon-rss:2048kB, file-rss:0kB

這代表 Linux 核心為了保護系統不當機,啟動了 OOM Killer,並選擇殺死分數 (Score) 最高、佔用最多記憶體的 httpd 進程。

2. 觀察當前記憶體壓力

使用 free -mvmstat 1 5 觀察。如果發現 Swap used 居高不下,且 CPU 長時間處於 wa (I/O Wait) 狀態,這表示系統正在瘋狂地進行記憶體置換 (Swapping),這是崩潰的前兆。

二、 鎖定嫌疑犯:誰吃光了記憶體?

確認是記憶體問題後,下一步是找出「大胃王」。使用 topps 進行排序:

ps aux --sort=-%mem | head -n 10

在 WordPress 環境中,通常會發現前幾名都是 httpd (Apache) 或 php-fpm。我們需要進一步分析單一進程的「真實」記憶體佔用:

  • VmRSS (Resident Set Size): 該進程實際佔用的物理記憶體。
  • 判斷準則:
    • 如果單個進程的 VmRSS 異常巨大,可能是程式碼有 Memory Leak。
    • 如果單個進程 VmRSS 正常(例如 80MB),但進程數量極多,則屬於「併發參數配置不當」。

三、 架構分析:為什麼多半是 MPM Prefork 出事?

Apache 的運作模式 (MPM) 決定了記憶體的消耗方式。實務上,90% 的 OOM 案例都發生在 Prefork 模式。

🔴 MPM Prefork (高風險)

機制: 一個連線 = 一個獨立 Process。

缺點: 記憶體開銷極大。假設每個 Process 佔 100MB,當有 100 個連線時,就吃掉 10GB 記憶體。在高併發時,實體 RAM 極易被耗盡。

🔵 MPM Event (推薦)

機制: 多進程 + 多執行緒 (Multi-threaded)。

優點: 一個 Process 可以處理多個請求。記憶體利用率高,極少發生單純因為 Event 模式導致的 OOM。

四、 容量規劃:如何計算「合理」的 Apache 配置?

無論使用哪種 MPM,核心邏輯都是數學問題:「你的車庫(記憶體)能停幾輛車(Process)?」

步驟 1:測出平均記憶體消耗

我們可以使用一段腳本,精準計算出當前環境下,平均每個 Apache 子進程佔用的記憶體大小:

ps -ylC httpd | awk '
  { x += $8; y += 1 }
  END {
    print "Apache Memory Usage (MB): " x/1024;
    print "Average Process Size (MB): " x/((y-1)*1024)
  }'

假設輸出結果為:平均每個 Process 約 100MB

步驟 2:計算 MPM Prefork 的 MaxRequestWorkers

這是最關鍵的一步。許多設定檔預設值為 150 或 256,但對於小記憶體主機來說,這是災難性的設定。

計算公式:
MaxRequestWorkers ≈ (總記憶體 - 系統預留記憶體) / 平均 Process 大小

範例試算:

  • 主機實體記憶體:16 GB
  • 預留給 OS / DB / 其他服務:4 GB
  • 可用給 Apache 的記憶體:12 GB

$$12,000 \text{ MB} / 100 \text{ MB} = 120$$

結論: 您的 MaxRequestWorkers 理論上限是 120。為了保留緩衝區(避免流量突增),建議設定在 100 左右。如果設定成 400,OOM 只是時間問題。

步驟 3:計算 MPM Event 的配置

Event 模式的計算稍微複雜一點,但邏輯相同。假設平均每個子進程約 10MB(Event 模式下較小),可用記憶體 7GB:

$$7,000 \text{ MB} / 10 \text{ MB} = 700 \text{ (最大並發線程數)}$$

在 Event 模式下,我們需要配置 ServerLimit (進程數) 與 ThreadsPerChild (每進程線程數)。

建議配置範例 (目標 600 並發):

  • ServerLimit 24
  • ThreadsPerChild 25
  • MaxRequestWorkers 600 (24 * 25)

五、 處置建議與總結

當您確認 OOM 發生後,請依循以下步驟處理:

  1. 緊急止血: 透過 systemctl restart httpd 釋放記憶體。若無效,暫時調整防火牆限制連線。
  2. 參數調校: 依據上述公式,修改 /etc/httpd/conf.modules.d/apache2.conf 中的 MaxRequestWorkers 數值。不要盲目調大,要「調準」。
  3. 壓力測試: 設定完成後,建議使用 httperf 或類似工具進行壓測,觀察錯誤率與回應時間,驗證設定是否穩定。
  4. 架構升級 (最終解法): 如果調校後記憶體依然不足,建議升級主機規格,或是參考我們的另一篇案例,導入負載平衡 (Load Balancing) 架構。

還是搞不定伺服器的不穩定問題?
複雜的 Linux 底層優化與參數調校,交給專業的技術團隊來處理。

預約 WordPress 效能診斷服務 →

Leave a Comment