Linux OOM Killer Tuning for VPS:實用指南
12 分鐘閱讀 - 2026年6月8日

調整您 VPS 上的 Linux OOM 殺手,以保護資料庫和 SSH、使用 cgroups 封鎖失控的進程,以及阻止錯誤的服務被殺死。
VPS 的 Linux OOM 殺手調校
當記憶體耗盡時,Linux OOM 殺手是核心的最後手段:它會選取一個程序並終止該程序,以維持系統運作。在 RAM 資源緊繃且無後備方案的 VPS 上,預設的選擇往往是錯誤的。 您的資料庫被終止,而一個長期運行的工作程序卻倖存下來,您只能自己去摸索原因。本指南將說明 OOM 殺手如何對程序進行評分、如何將評分優先權偏向您的關鍵服務,以及如何使用 cgroups,以防止單一失控程序拖垮整個系統。
OOM 殺手如何選擇犧牲品
當核心無法透過頁面快取驅逐或交換空間回收足夠的記憶體時,便會啟動 OOM 殺手。每個程序都有一個 oom_score 0 到 1000 之間的分數,該分數主要根據其駐留集大小 (RSS) 和交換空間使用情況計算得出。分數最高的進程將收到 SIGKILL 訊號。
RSS 在計算中佔主導地位,這也是為何終止操作幾乎總是落在記憶體消耗最大的進程上。這通常是您的資料庫、應用伺服器,或是任何正在執行最重要工作的長壽進程。實際觸發分配的進程(即「呼叫者」)極少會被終止。
您需要區分以下兩種 OOM 事件:
- 全局 OOM:主機(或您的 VPS 整體)已耗盡 RAM 和交換空間。核心會掃描每個進程,並終止得分最高的進程。
- cgroup OOM:特定 cgroup 已達到其記憶體限制。即使系統其餘部分仍有閒置記憶體,核心也只會在該 cgroup 內部終止進程。
若您已設定 systemd 單元限制,或正在運行容器,多數 OOM 事件將屬於 cgroup OOM。這其實是好事:影響範圍得以控制。
在系統當機前偵測記憶體壓力
OOM 事件幾乎從不會突然發生。通常會先出現一段壓力逐漸加劇的預警期,而監控的目標正是要在該預警期內及時察覺。
free -h 提供系統概覽。關鍵的欄位是 available,而非 free:它代表可回收的頁面快取,反映了在不進行交換的情況下實際可分配的記憶體量。請將 MemAvailable 維持在峰值負載的 10% 至 15% 左右 MemTotal 。
若要進行按進程歸因分析,請依 RSS 排序:
ps aux --sort=-%mem | head -10或使用 htop 並依 RES。此處顯示的數值會直接納入核心的評分機制,因此排在前幾名的項目最有可能成為 OOM 的目標。
在 4.20 及更新版本的內核中,「壓力滯留資訊」是值得整合至監控系統的早期預警機制:
cat /proc/pressure/memory該 some avg10 圖表顯示過去十秒內,至少有一項任務因等待記憶體而陷入停滯的時間占比。低於 5% 即屬正常。若數值持續高於 10%,表示系統正耗費實時資源卡在記憶體回收上,此時發生 OOM 強制終止程序的可能性很高。
交換空間抖動會顯示在 vmstat 1 中以非零 si 和 so 欄位中持續出現。少量駐留的交換空間無害,但持續不斷的交換進與交換出則不然。
使用 oom_score_adj 保護關鍵程序
核心計算出的分數可透過 oom_score_adj,調整範圍從 -1000(免疫)到 +1000(優先終止)。此調整值將直接加到最終分數上。
若要對正在執行的程序進行一次性變更:
echo -500 | sudo tee /proc/$(pidof sshd)/oom_score_adj若需讓設定在系統重啟後持續生效,請在 systemd 單元中設定。這正是 sshd、您的資料庫,以及任何您無法承受損失的服務的正確設定位置:
[Service]
OOMScoreAdjust=-900合理的預設起始值:
- sshd:-1000。若在記憶體危機期間失去遠端存取能力,後續復原將困難許多。
- MySQL、PostgreSQL、Redis:-800 至 -900。提供強效保護,同時確保在真正災難性情況下仍可對其進行干預。
- 應用程式工作執行程序、批次工作、cron 任務:+100 至 +500。這些是您寧可看到它們被終止,也不願讓資料庫受影響的程序。
請勿將所有設定都設為 -1000。若沒有任何進程可被終止,核心最終會陷入恐慌或凍結狀態,情況反而更糟。
使用 cgroups 和 systemd 限制記憶體
調整評分會影響哪些進程被終止。cgroups 則決定是否會觸發全局終止機制。透過為每個服務設定嚴格的上限,可將記憶體異常限制在單一 cgroup 內,而非讓單一進程耗盡整個 VPS 的資源。
在 systemd 單元檔案中:
[Service]
MemoryHigh=400M
MemoryMax=512M
OOMPolicy=stop
Restart=on-failure
RestartSec=5sMemoryHigh 是軟性限制:當使用量超過此值時,核心會積極從該 cgroup 回收頁面,但不會終止任何進程。 MemoryMax 是硬性上限。若 cgroup 嘗試分配超過此上限,核心會終止該 cgroup 內的某個程序。透過 Restart=on-failure 該服務會立即重新啟動。
在 cgroup v2 環境下(Ubuntu 22.04 及後續版本、近期 Debian、RHEL 9), memory.oom.group 會將 cgroup 中的所有進程一併終止,而非留下孤兒進程。這對於 PHP-FPM 池等多進程服務特別有用,因為若僅終止部分進程,該群組可能會出現異常行為。
以下是幾項值得參考的應用程式特定注意事項:
- PHP-FPM:設定
pm = ondemand於小型 VPS 實例上,並將pm.max_children時,應參照每個工作執行程式的平均 RSS 值,而非預設值。若在 2 GB 的 VPS 上將池大小設定為保留 4 GB 空間,當記憶體填滿時便會首次觸發 OOM 錯誤。 - Node.js:使用
--max-old-space-size=512(單位為 MB)。若未設定,Node 會持續擴張直至核心介入為止。 - MySQL 與 PostgreSQL:
innodb_buffer_pool_size以及shared_buffers應為作業系統的頁面快取、連線記憶體以及伺服器上的其他租戶預留充足的餘裕空間。預設值是基於專用伺服器的假設。
在發生 OOM 事件後讀取日誌
當 OOM 殺手觸發時,核心會將詳細報告寫入環形緩衝區。請使用以下指令讀取:
dmesg -T | grep -iE 'killed process|out of memory'
journalctl -k --grep='Out of memory'需仔細閱讀的區段以「invoker」開頭,並以「victim」結尾。核心會列印完整的任務清單,包含每個進程的 RSS、交換空間使用量以及最終 oom_score_adj。有三項內容值得檢查:
- 限制條件。
CONSTRAINT_NONE表示全域 OOM,CONSTRAINT_MEMCG表示 cgroup 觸及其限制。兩種情況的解決方式各不相同。 Free swap。若此處顯示0kB,表示 RAM 和交換空間皆已耗盡。可選擇增加交換空間、提高MemoryMax肇事進程的權重,或是降低並發度。- 受害進程的評分與其他所有進程的比較。若受害進程的評分僅略高於後幾項進程,則您的
oom_score_adj設定的數值未能發揮足夠作用。請擴大分差。
針對 cgroup 記憶體不足 (OOM) 情況,kill 計數器位於 memory.events cgroup 內部:
cat /sys/fs/cgroup/system.slice/mysql.service/memory.events計數器 oom_kill 計數值上升,表示該服務正反覆觸及其限制。這是一個訊號,表示應提高 MemoryMax、分析工作負載,或是將服務移至更大的資源方案,而非不斷循環重啟該服務。
總結
調整 OOM 殺手並非為了讓它消失,而是為了控制在記憶體耗盡時由哪個程序承擔代價,並在發生時縮小影響範圍。在生產環境中,以下模式是行之有效的:
- 為您無法承受損失的服務設定 Score-protect,尤其是 sshd 和您的資料庫。
- 將其餘所有服務
MemoryMax,將其納入 systemd 單元中,如此一來,即使有單一程序失控,也只需重新啟動該服務,而非導致系統中斷。 - 監控 PSI 並
MemAvailable,而非等待dmesg事後才透過 PSI 得知狀況。 - 預留 15% 至 20% 的 RAM 作為緩衝空間。即使進行調校,也無法彌補 VPS 容量根本不足以應付工作負載的問題。
若您的記憶體壓力屬於結構性問題而非可透過設定解決,您需要更多 RAM 或更快的交換區儲存裝置。FDC Servers 的 VPS 方案採用 AMD EPYC 處理器搭配 NVMe 儲存裝置,這能確保交換區讀取速度足夠快,使短暫的記憶體爆滿不會演變成系統強制終止。

Linux OOM Killer Tuning for VPS:實用指南
調整您 VPS 上的 Linux OOM 殺手,以保護資料庫和 SSH、使用 cgroups 封鎖失控的進程,以及阻止錯誤的服務被殺死。
12 分鐘閱讀 - 2026年6月8日
Linux 流量控制 (tc):實用指南
12 分鐘閱讀 - 2026年6月5日