萬盛學電腦網

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

MySQL "Too many connections" 連線數耗盡:根因分析與多層級解決方案

錯誤現象

ERROR 1040 (HY000): Too many connections

應用報錯、新連線被拒、現有連線可能卡死。

根因分層排查

第 1 層:應用層洩漏(最常見)

  • PHP mysqli_close() 未調用、連線池未釋放
  • 長時間執行腳本(爬蟲、報表)佔用連線不釋放
  • 框架配置錯誤導致持久連線堆積

排查:

SHOW PROCESSLIST;
-- 觀察 Command=Sleep、Time 較大、Info=NULL 的連線

第 2 層:慢查詢堵塞

  • 大表掃描、鎖等待、未命中索引
  • 連線被長時間佔用,新連線排隊

排查:

SHOW FULL PROCESSLIST;
-- 找 Time 大、State=Sending data/Locked 的查詢
-- 配合 slow_query_log 定位

第 3 層:架構層面(真實案例)

某電商大促:Web 節點一台掛掉 → 流量湧向剩餘節點 → PHP-FPM 處理變慢 → MySQL 連線釋放延遲 → 連線數飆升 → 雪崩。

對策:

  • 啟用 PHP-FPM pm.max_requests 定期回收進程
  • 設定 request_terminate_timeout 防止卡死
  • 應用層熔斷/限流(Sentinel、Guzzle retry+timeout)
  • 資料庫層 max_connections 預留緩衝

解決方案

緊急臨時調大(線上生效,重啟失效)

mysql> SET GLOBAL max_connections = 2000;

永久調大(配置檔)

[mysqld]
max_connections = 2000
# 配套調大
open_files_limit = 65535
table_open_cache = 4000
innodb_open_files = 4000

重啟生效。注意:每連線約消耗 256KB~2MB 記憶體,2000 連線需 1-4GB 額外 RAM。

Windows 註冊表/配置檔修改

# my.ini
[mysqld]
max_connections = 2000

重啟服務:net stop mysql && net start mysql

Linux 編譯安裝修改源碼(極少用)

# sql/mysqld.cc
{"max_connections", ..., 2000, 1, 100000, ...}  # 預設值改為 2000
# 重新編譯安裝

監控與告警

# 關鍵指標
SHOW STATUS LIKE 'Threads_connected';    -- 當前連線數
SHOW STATUS LIKE 'Max_used_connections'; -- 歷史峰值
SHOW STATUS LIKE 'Aborted_connects';     -- 被拒連線數

# Prometheus + Grafana 告警規則
mysql_global_status_threads_connected / mysql_global_variables_max_connections > 0.8

最佳實踐總結

  1. 預設 max_connections=151 太小,生產環境起步設 500-1000
  2. 連線池大小 < max_connections / Web節點數,留 20% 緩衝
  3. 嚴禁持久連線 pconnect,改用短連線 + 連線池
  4. 慢查詢、鎖等待、大事務是隱形殺手,建立慢查詢日誌告警
  5. 架構層面:讀寫分離、分庫分表、快取層(Redis)分攤讀壓力
copyright © 萬盛學電腦網 all rights reserved