首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL OOM 系列(三):MySQL 免殺三板斧——內存規劃、oom_score_adj、監控熔斷

     編輯:MySQL 綜合教學

前言

前兩篇揭示:Linux OverCommit 讓 MySQL 成為 OOM Killer 首選目標,禁用 OverCommit 反而增加 Crash 風險。本文給出生產環境驗證的「免殺三板斧」,構建從預防、保護到兜底的立體防禦體系。

一、板斧一:合理規劃 MySQL 內存佔用(源頭控制)

1.1 內存佔用模型

Total MySQL Memory ≈
  Global Buffers
  + (Thread Buffers × Max Connections)
  + Other (Table Cache, Dict, PS, etc.)

1.2 關鍵參數與建議值(以 16GB 實例為例)

參數建議值佔比/說明
innodb_buffer_pool_size10-11 GB60-70% 物理內存,核心緩存
innodb_buffer_pool_instances8-16減少鎖競爭
innodb_log_buffer_size64-128 MB大事務減少刷盤
max_connections2000-3000配合連接池,避免爆發
thread_stack256 KB默認足夠
sort_buffer_size2-4 MB會話級,慎調大
join_buffer_size2-4 MB會話級,慎調大
read_buffer_size2-4 MB會話級
read_rnd_buffer_size2-4 MB會話級
binlog_cache_size32 MB事務級
table_open_cache4000-8000減少打開表開銷
table_definition_cache2000-4000
query_cache_size05.7+ 建議關閉

1.3 理論峰值估算

Global ≈ 11.5 GB
Per Thread ≈ 16 MB (sort+join+read+read_rnd+binlog+stack)
Max Threads ≈ 3000
Peak ≈ 11.5 + 16×3000/1024 ≈ 59.5 GB  ← 理論值,實際遠低(並非所有連接同時滿載)

# 實際建議:物理內存預留 20-30% 給 OS、FS Cache、監控 Agent、備份進程
# 16GB 實例:MySQL 佔用 ≤ 12 GB,留 4 GB 給系統

二、板斧二:設置 oom_score_adj = -800(核心保護)

2.1 為什麼不是 -1000?

  • -1000 = 完全免疫,系統內存耗盡時無進程可殺 → 內核崩潰/重啟
  • -800 = 分數右移 800 位,實際 oom_score 極低但非零,極端情況仍可被犧牲,保住系統

2.2 生效方式

# 方法 1:systemd 服務單元(推薦,持久化)
# /etc/systemd/system/mysqld.service.d/override.conf
[Service]
OOMScoreAdjust=-800

systemctl daemon-reload && systemctl restart mysqld

# 方法 2:啟動腳本注入
echo -800 > /proc/$(pgrep mysqld)/oom_score_adj

# 方法 3:mysqld_safe 封裝
# 在 mysqld_safe 中添加調用

2.3 驗證

cat /proc/$(pgrep mysqld)/oom_score_adj   # -800
cat /proc/$(pgrep mysqld)/oom_score       # 極低值(如 0-10)

三、板斧三:內存水位監控 + 自動熔斷(兜底防線)

3.1 監控指標體系

層級指標告警閾值動作
OSMemAvailable / MemTotal< 15%觸發熔斷
OSSwapUsed / SwapTotal> 10%緊急排查
MySQLInnodb_buffer_pool_pages_total × page_size / RAM> 75%評估擴容
MySQLThreads_connected / max_connections> 80%限流/擴容
MySQLPerformance Schema memory summary內存組件異常增長定位泄漏

3.2 熔斷腳本示例

#!/bin/bash
# 每分鐘跑一次,檢測 MemAvailable < 15% 則 Kill 閒置連接
AVAIL_PCT=$(awk '/MemAvailable/{a=$2} /MemTotal/{t=$2} END{print int(a*100/t)}' /proc/meminfo)
if [ $AVAIL_PCT -lt 15 ]; then
  # Kill 睡眠超過 60s 的非超級用戶連接
  mysql -e "SELECT CONCAT('KILL ', id, ';') FROM information_schema.PROCESSLIST
            WHERE COMMAND='Sleep' AND TIME>60 AND USER NOT IN ('root','repl','monitor')
            ORDER BY TIME DESC LIMIT 50" | mysql
  logger "MySQL OOM Fuse triggered: killed idle connections, MemAvailable=$AVAIL_PCT%"
fi

3.3 進階:ProxySQL 查詢熔斷

  • mysql-query_rules:匹配高耗時/大結果集查詢 → ERROR_MSG 直接返回
  • mysql_scheduler:定期執行 KILL QUERY 清理長運行事務

四、實戰案例:4GB RDS 實例免殺記

  • 現狀:Buffer Pool 2.5GB、Max Conn 1000、無 oom_score_adj、無監控熔斷 → 月均 1-2 次 OOM Kill
  • 整改:Buffer Pool 2GB、Max Conn 500、oom_score_adj=-800、部署熔斷腳本
  • 效果:連續 6 個月零 OOM Kill,內存水位穩定在 65-75%

五、總結

MySQL OOM 免殺無銀彈,只有源頭控制內存佔用、核心調低 oom_score、兜底監控熔斷的組合拳。將三板斧納入標準化部署模板、巡檢清單、變更驗收標準,讓 OOM 成為可控風險而非不可預測的黑天鵝。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved