萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL "Too many connections" 徹底解決指南:從緊急處理到架構優化

錯誤現象與核心成因

ERROR 1040 (HY000): Too many connections 表示當前連線數已達 max_connections 上限。根本原因通常有二:

  1. 設定值偏低: 預設 151,生產環境遠不夠用。
  2. 連線洩漏/未釋放: 應用端(如 Java 連線池)未正確關閉連線,或 wait_timeout 過長導致閒置連線堆積。

方案一:修改配置檔並重啟(標準流程,需停機窗口)

# /etc/my.cnf
[mysqld]
max_connections = 1000
wait_timeout = 300          # 閒置 5 分鐘自動斷開,防洩漏
interactive_timeout = 300
# 可選:限制單一用戶最大連線,防單點佔滿
max_user_connections = 200

修改後 systemctl restart mysqld 生效。

方案二:不重啟動態調整(緊急救援,立即生效)

利用 gdb 附掛到運行中的 mysqld 進程,直接修改記憶體中的全域變數:

gdb -p $(cat /var/run/mysqld/mysqld.pid) \
    -ex "set max_connections=500" -batch

驗證:

mysql -e "SHOW VARIABLES LIKE 'max_connections';"
# +-----------------+-------+
# | Variable_name   | Value |
# +-----------------+-------+
# | max_connections | 500   |
# +-----------------+-------+

原理: max_connections 屬於動態全域變數(SET GLOBAL 生效),但若配置檔未同步修改,重啟後會還原。緊急調大後務必同步更新 my.cnf。

方案三:Percona/XtraDB 專屬「後門」連線

Percona Server 5.5+ 內建 thread_pool 提供兩個參數:

  • extra_port(預設 10086):額外監聽埠,僅供管理員連線
  • extra_max_connections(預設 1):該埠允許的最大連線數

即使主埠連線已滿,管理員仍可透過 mysql -P 10086 -u root -p 進入執行 KILL 或調整參數。強烈建議啟用並設定 extra_max_connections=5 以上。

架構層面的根治策略

1. 連線池正確配置(以 HikariCP / Druid 為例)

# 關鍵參數
maximumPoolSize = 30          # 應用實例數 × 此值 < max_connections
minimumIdle = 5
idleTimeout = 300000          # 5 分鐘,配合 wait_timeout
maxLifetime = 1800000         # 30 分鐘強制換新,防驅動端殘留
connectionTimeout = 5000      # 獲取連線超時 5 秒,快速失敗

2. 啟用 Thread Pool(Percona / MariaDB / MySQL 8.0+)

將「一連線一執行緒」改為「池化工作執行緒」,大幅降低高併發下的上下文切換開銷,單機可支撐 5,000+ 併發連線。

3. 監控與告警

  • Prometheus + mysqld_exporter 采集 Threads_connected / max_connections
  • 告警閾值:Threads_connected / max_connections > 0.8 觸發預警,> 0.95 觸發緊急處理

Java 應用端常見堆疊與對策

Data source rejected establishment of connection
message from server: "Too many connections"
at com.mysql.jdbc.MysqlIO.checkErrorPacket...

除了上述資料庫端調整,應用端必須:

  1. 確認 @Transactional 正確宣告,避免長事務佔住連線。
  2. 檢查是否有「查詢後忘記 close()」的手動 JDBC 代碼。
  3. Tomcat server.xml 中 <Resource> 設定 maxTotal、maxIdle、removeAbandoned=true。

關聯議題:innodb_log_file_size 變更導致無法啟動

調整 innodb_log_file_size 後,必須先停庫、刪除舊 ib_logfile*,再啟動:

systemctl stop mysqld
rm -f /var/lib/mysql/ib_logfile*
systemctl start mysqld

否則 InnoDB 啟動時檢測到 redo log 大小不符會直接中止。

copyright © 萬盛學電腦網 all rights reserved