在低記憶體VPS上運行Debian 12:如何減少MySQL記憶體不足崩潰

在低記憶體的 Debian 12 VPS 上,您可以透過確認原因、合理分配所有服務的記憶體、限制資料庫並發以及在 VPS 允許的情況下提供交換空間來降低 OOM killer 導致 MySQL 停止運行的風險。僅僅縮小 InnoDB 緩衝池並不能徹底解決問題。無論是交換空間還是 OOM 保護設置,都無法保證過大的工作負載能夠持續運作。

本指南於 2026 年 10 月 9 日基於 Debian 12 “bookworm”、Linux 6.1 和 Oracle MySQL 8.0/8.4 文件編寫完成。以下設定僅供參考,並非基準測試結果或一般配置。更改資料庫和配置前請務必備份,並在可接受停機時間的情況下安排資料庫重新啟動。

1. 在複製 MySQL 設定之前,請先確定伺服器。

已驗證: Debian 12 的預設 MySQL 伺服器軟體包依賴 MariaDB。一台被描述為運行「MySQL」的 VPS 實際上可能運行的是 MariaDB,而另一台 VPS 則可能運行的是來自獨立倉庫或容器的 Oracle MySQL。

mysql --version
systemctl status mysql mariadb

第一條命令用於識別客戶端,但不能確定正在執行的伺服器。請使用資料庫管理員帳戶連線並執行:

SELECT VERSION(), @@version_comment;

使用您現有的身份驗證方法;Debian MariaDB 安裝可能允許使用本機管理sudo mysql。記錄伺服器版本和實際服務名稱。後續服務指令使用 `<service_name>` mysql.service;mariadb.service在適當情況下進行替換。不要將僅適用於 Oracle 的變數新增至 MariaDB 配置中。

用於檢查資料庫用戶端版本和 MySQL 或 MariaDB 服務狀態的終端命令範例。
檢查客戶端和服務名稱,然後查詢正在執行的伺服器以確定產品和版本。

2. 確認此關機是由記憶體不足 (OOM) 事件引起的。

常見誤解:任何無故重啟資料庫都會導致記憶體溢位 (OOM) 導致的服務中斷。身份驗證錯誤、磁碟耗盡、配置無效、系統崩潰以及管理員重新啟動等操作也可能導致服務中斷。

sudo journalctl -k -b
sudo journalctl -u mysql.service --since today
sudo journalctl -u systemd-oomd --since today

在事件發生前後,尋找核心訊息,確認是否有記憶體不足的情況以及被終止的進程,然後將這些訊息與服務日誌進行比對。如果您的軟體包將錯誤日誌寫入檔案而非日誌,也請檢查資料庫錯誤日誌。如果事件發生在重新啟動之前,請檢查上次啟動journalctl -k -b -1時保留的日誌。缺少歷史日誌將導致無法確認事件原因。

使用者空間管理器也可以終止工作負載。 Debian 的systemd-oomd 手冊描述了在核心發生記憶體溢位 (OOM) 事件之前,基於記憶體壓力進行幹預的方法。請檢查程式是否已安裝並處於活動狀態,而不是想當然地認為每個 Debian VPS 都使用它。

同時檢查 systemd 的限制:

systemctl show mysql.service \
  -p ControlGroup -p MemoryCurrent -p MemoryHigh \
  -p MemoryMax -p MemorySwapMax

在 cgroup v2 系統中,使用報告的 ControlGroup 路徑讀取 `<controlGroup_path>` memory.events、memory.max`<controlGroup_path>` 和 `<controlGroup_path> memory.swap.max` 下的/sys/fs/cgroup`<controlGroup_path>` 和 `<controlGroup_path>`。同時檢查父 cgroup。 Linux cgroup v2 文件解釋了這些計數器和限制。即使主機記憶體充足,cgroup 也可能耗盡其允許的記憶體。計數器會oom_kill記錄終止操作,但必須結合限制和日誌進行解讀才能確定原因。

用於檢查核心和資料庫服務日誌的終端命令範例。
在將資料庫中斷歸因於記憶體不足之前,請檢查事件發生時的日誌。

3. 測量整個VPS,而不僅僅是緩衝池。

free -h
ps -eo pid,comm,rss --sort=-rss
vmstat 1

在正常流量期間以及與故障相關的作業期間收集觀測資料。在日誌中free,重點關注可用內存,而不僅僅是空閒內存列。 Debian 的空閒記憶體手冊將可用記憶體描述為不使用交換空間時可使用的記憶體的估計值。進程列表中的 RSS 值以 KiB 為單位;將它們相加可能會導致共享記憶體重複計算。

已驗證: MySQL 會分配超出 InnoDB 緩衝池範圍的內存,包括連接和查詢相關的內存分配。 MySQL記憶體使用參考文件中記錄了這些元件。請將基於已配置緩衝區的公式視為規劃估算,而非精確的上限。

措施:為核心、Web Worker、監控、備份和臨時資料庫工作預留足夠的記憶體。在共享 VPS 上,不進行任何調整就將大部分記憶體分配給 InnoDB 資料庫,這是常見的做法。如果 PHP Worker 或建置任務佔用了可用內存,請調整或遷移這些工作負載,而不是重複縮減 MySQL 的記憶體。

可用記憶體、進程 RSS 和 vmstat 監控的終端命令範例。
在代表性活動中測量所有競爭過程和記憶壓力。

4. 增加交換空間作為緩衝區,而不​​是取代 RAM

取決於具體情況:MemorySwapMax交換空間可以緩解一些臨時的匿名記憶體壓力,但持續的交換會導致查詢速度過慢。基於容器的虛擬專用伺服器 (VPS) 可能會限制交換空間的使用,即使主機支援交換空間,某些服務也可能阻止其使用。

swapon --show
free -h
df -h /
findmnt -no FSTYPE /

如果不存在交換分割區,且服務提供者允許,且您有足夠的磁碟空間,以下指令會在適當的本機檔案系統(例如 ext4)上建立一個 1 GiB 的交換檔案。如果 /swapfile 已存在,請勿執行此命令。請先查看檔案系統的具體要求;Btrfs 需要適當的非寫入時複製 (no-copy-on-write) 交換檔案設定。

sudo dd if=/dev/zero of=/swapfile bs=1M count=1024 status=progress
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
swapon --show

啟動成功後,再將此條目加入/etc/fstab:

/swapfile none swap sw 0 0

Debian swapon 手冊中記錄了交換文件的限制。如果 VPS 環境拒絕激活,請諮詢服務提供者以了解支援的交換檔案大小或增加套餐記憶體;不要保留失敗的設定。

不要將「將交換分區優先權設為零」這樣的調整作為記憶體溢位保護措施。核心虛擬機器文件將交換分區優先權定義為一種記憶體回收成本偏好設置,它不會建立記憶體或限制資料庫記憶體。建議初始設定保持不變,並觀察系統行為。

用於檢查活動交換空間、磁碟空間和根檔案系統類型的終端機命令範例。
在決定是否使用交換文件之前,請檢查交換分割區和檔案系統狀況。

5. 設定一個適度的資料庫基線。

舉例來說,考慮一台 1 GiB 的 VPS,上面運行著少量 InnoDB 工作負載和幾個應用程式工作進程。以下數值僅供評估參考,並非證明該工作負載符合要求的證據:

[mysqld]
innodb_buffer_pool_size=128M
max_connections=20
tmp_table_size=16M
max_heap_table_size=16M

將伺服器選項放在安裝程式實際包含的設定檔中。 Oracle MySQL 軟體包可能包含`<filename> /etc/mysql/mysql.conf.d/`;Debian MariaDB 通常使用 ` /etc/mysql/mariadb.conf.d/<filename>`。請驗證現有的包含指令並保留備份。 MySQL 的選項文件文件解釋了伺服器選項組和文件處理。

128 MiB 的緩衝池限制的是緩存,而不是資料庫總記憶體。如果多個應用程式實例各自維護一個緩衝池,則 20 個連線的限制可能過於嚴格。反之,20 個並發的繁重查詢仍然可能導致 VPS 過載。應用程式集的總連線數應控制在伺服器預期限制以下,並預留管理存取空間,同時密切注意連線被拒絕的情況。

上述常用變數也出現在 MariaDB 的系統變數參考文件中,但臨時表的行為會因產品和版本而異。在資源受限的機器上,切勿透過增加全域排序、連線或讀取緩衝區大小來提升效能。

終端機顯示 mysqld 配置範例,其中緩衝池為 128M,連線數限制為 20。
這些小型伺服器設定只是一個評估的起點,而不是資料庫總記憶體的上限。

6. 同時控制臨時表和並發性

常見誤解:設定tmp_table_size=16M上限會將所有查詢記憶體限制在 16 MiB。事實並非如此。多個會話、多個臨時表和其他執行分配可以共存。

對於Oracle MySQL 8.4,另一個可供參考的起點是:

temptable_max_ram=64M
temptable_max_mmap=0

僅在確認產品支援後,才能將這些參數新增至現有[mysqld]組。它們控制 TempTable 引擎的共享記憶體閾值和記憶體映射臨時檔案的使用。它們不會限制整個 mysqld 進程或所有線程局部記憶體分配。較低的閾值可能會將更多工作推送到磁碟。

MySQL 8.4 臨時表文檔解釋了這些限制。 MySQL 8.0 的行為與版本相關:此限制temptable_max_mmap在 8.0.23 版本中引入,並tmp_table_size在 8.0.28 版本中成為單一 TempTable 的限制。在套用相同設定之前,請先查閱MySQL 8.0 參考文件。請勿將這些 Oracle 特有的選項複製到 MariaDB。

措施:限制重疊的報表查詢、背景工作進程以及備份或匯入作業。當特定操作導致系統壓力過大時,應檢查查詢計劃和索引。將過大的工作負載移出高峰期有助於解決問題;如果正常的並發需求仍然超過容量,則下一步應考慮增加記憶體或分離資料庫。

終端機顯示 Oracle MySQL TempTable 範例設置,記憶體為 64M,記憶體映射分配已停用。
請僅將這些臨時表設定套用至支援的 Oracle MySQL 版本,並遵循特定版本的指導。

7. 驗證變更並故意重啟

對於支援此選項的 Oracle MySQL 版本,請在重新啟動前檢查配置:

sudo mysqld --validate-config

如果服務未使用預設設定發現,請使用與服務相同的預設檔案路徑和相關啟動參數。 MySQL驗證參考文件指出,驗證並不會初始化每個子系統。通過驗證並不代表工作負載容量測試通過。請勿假定 MariaDB 支援此 Oracle 選項。

在計劃的時間視窗內重新啟動實際服務,然後檢查啟動情況並查詢有效值:

sudo systemctl restart mysql.service
systemctl status mysql.service
sudo journalctl -u mysql.service --since today
SHOW GLOBAL VARIABLES WHERE Variable_name IN
('innodb_buffer_pool_size','max_connections','tmp_table_size',
 'max_heap_table_size','temptable_max_ram','temptable_max_mmap');
SHOW GLOBAL STATUS WHERE Variable_name IN
('Threads_connected','Threads_running','Max_used_connections');

不支援的變數不會出現在結果中。請驗證預期設置,不要想當然地認為新文件會優先生效。如果由於您的變更導致啟動失敗,請恢復已儲存的配置,或僅移除新的覆蓋設置,然後重新啟動。請保留錯誤詳細資訊以便診斷。

終端機顯示 Oracle MySQL 驗證、服務重新啟動和 service-status 指令範例。
在計畫重新啟動之前,請先驗證 Oracle MySQL 設定是否受支援;啟動成功並不代表記憶體充足。

8. 在典型負荷下定義成功。

free -h
vmstat 1
cat /proc/pressure/memory

比較變更前後相同的流量和規劃任務。追蹤新的記憶體溢位事件、資料庫重新啟動、可用記憶體、連線拒絕、交換活動和查詢延遲。vmstat持續的換入/換出操作值得調查。 Debian vmstat 手冊解釋說,第一份報告反映的是自啟動以來的平均活動情況;後續報告則反映的是當前速率。

內核PSI 參考文件描述了壓力停滯測量方法。增加記憶體停滯時間可以在發生另一次系統崩潰之前就發現問題。空閒系統存活十分鐘並不能證明下一次備份或流量突發是安全的。

終端機顯示可用記憶體、vmstat 和記憶體壓力檢查指令範例。
更改後,監控記憶體、交換活動和壓力以及查詢延遲。

有些誤解可能會使問題更加嚴重。

宣稱應該怎麼做?
保護mysqld免受OOM(記憶體溢出)的影響,記憶體不足的問題就會消失。減少需求或增加產能;改變受害者的選擇可以將故障轉移到另一個流程。
設定較小的 MemoryMax 值,使 MySQL 能夠適應。首先檢查現有限制並調整工作負載;硬性限制可能會觸發服務內部的記憶體溢位 (OOM)。
自動重啟後資料庫穩定。使用重啟行為進行恢復,同時測量原始壓力是否仍然存在。
停用持久化設定以節省記憶體。將恢復和耐久性要求與記憶體調優分開。

Debian 的systemd 資源控製手冊解釋說,它MemoryMax可以在單元內部觸發 OOM 處理。不要盲目地移除提供者或容器的限制。應用程式需要符合這些限制的記憶體預算,或需要對限制進行授權的容量變更。

目前尚無經過驗證的最小 VPS 配置能夠保證此特定工作負載正常運作。如果有效吞吐量需要持續的記憶體交換,如果計劃任務仍然會觸發終止,或者如果較小的快取導致延遲無法接受,則不應再將配置視為容量的替代方案。請升級記憶體、降低應用程式並發度或將資料庫遷移到單獨的服務。

留下評論

使用 Systemd 定時器可靠地執行 ownCloud 後台作業

將按需作業運行替換為 systemd 定時器,該定時器每 15 分鐘執行一次 ownCloud 支援的 occ system:cron 命令。

透過尋找故障路由來恢復 ownCloud WebDAV 同步

透過 Apache、Nginx 或反向代理程式追蹤 WebDAV 請求,然後使用經過驗證的 PROPFIND 測試確認 ownCloud 同步功能正常。

設定 Nextcloud 的公共 URL,以便它可以存取自身。

透過設定其規範 URL 並從伺服器本身檢查 DNS、HTTPS 和反向代理路由,修復 Nextcloud 缺少出站位址警告的問題。

在 Ubuntu 24.04 上設定 Nextcloud Redis 快取

在 Ubuntu 24.04 上設定 Nextcloud Redis 快取

透過本機 Unix 套接字配置 APCu 和 Redis,以實現 Nextcloud 快取和檔案鎖定,並提供目前和舊版 Nextcloud 的步驟。

使用 Systemd 定時器自動執行 Nextcloud Cron

檢查 Nextcloud 的 cron 模式,修復其 systemd 服務和計時器,並驗證後台作業在啟動後以及每隔五分鐘運行一次。

使用 Redis 清除 Nextcloud 的檔案鎖定警告

啟用可靠的 Nextcloud 檔案鎖定,選擇適當的 Redis 或 Valkey 後端,並驗證警告是否清除,同時避免並發檔案變更的風險。

如何才能獲得 Nextcloud A+ 安全評級

如何才能獲得 Nextcloud A+ 安全評級

使用最新更新、HTTPS 和 HSTS、精確的反向代理信任以及針對公共伺服器的檢查,修復 Nextcloud 掃描中常見的錯誤。

啟用 Nextcloud 伺服器端加密,並評估其影響

為需要加密的儲存配置 Nextcloud SSE,保護加密金鑰,並在加密現有文件之前測量傳輸和 CPU 影響。

將 Elasticsearch 全文搜尋功能新增至 Nextcloud

將 Nextcloud 的檔案搜尋連接到 Elasticsearch,索引文件內容,並選擇適合您的伺服器和安全需求的設定。

為 Nextcloud 已刪除檔案設定可靠的過期策略

為 Nextcloud 已刪除檔案設定可靠的過期策略

配置 Nextcloud 在規定的保留期後刪除已刪除的文件,可靠地安排後台作業,並避免執行清除所有使用者回收站的命令。