萬盛學電腦網

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

MySQL Sleep 連線過多問題:成因分析與三大解決方案

大量 Sleep 狀態連線會佔用 max_connections 額度,導致新請求被拒、資源浪費甚至服務不可用。本文解析三大根因,提供配置調整、程式碼修正與連線池優化三層次解決方案。

一、Sleep 連線產生的三大原因

  1. 程式未顯式關閉連線:PHP/Java/Python 等未呼叫 mysql_close()/conn.close(),或連線池配置不當導致閒置連線不釋放。
  2. 閒置超時未達閾值:客戶端在 wait_timeout (非互動) 或 interactive_timeout (互動) 秒數內無操作,連線仍保持開啟。
  3. 客戶端異常中斷:請求發出後進程崩潰/網路斷開,Server 端未收到 FIN 包,連線處於半開狀態。

二、快速緩解:縮短超時時間

修改 /etc/my.cnf:


[mysqld]
wait_timeout = 60        # 非互動連線 60 秒無操作自動斷開
interactive_timeout = 60 # 互動式連線 (如 CLI) 同理

或線上熱修改 (重啟後失效):


SET GLOBAL wait_timeout = 60;
SET GLOBAL interactive_timeout = 60;

生產驗證: 將預設 28800 秒 (8小時) 降至 60 秒,Sleep 連線數立即下降 90%+,QPS 穩定。

三、根治方案:應用層修正

1. 拒絕持久連線


// PHP 錯誤示範
$link = mysql_pconnect(...); // 持久連線,易殘留 Sleep
// 正確
$link = mysql_connect(...);  // 短連線,請求結束自動釋放

2. 確保顯式關閉 / 使用連線池正確歸還


// PHP PDO 範例
try {
    $pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_PERSISTENT => false]);
    // 業務邏輯
} finally {
    $pdo = null; // 顯式釋放
}

// Java HikariCP 關鍵配置
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.idle-timeout=30000      // 30秒閒置回收
spring.datasource.hikari.max-lifetime=1800000    // 30分鐘強制換新
spring.datasource.hikari.connection-timeout=5000

3. 異常處理確保釋放

所有資料庫操作包裝在 try-finally 或 with / using 區塊,確保異常路徑也能釋放連線。

四、監控與告警


-- 即時查看
SHOW PROCESSLIST;
-- 或
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND='Sleep';

-- 監控腳本 (每分鐘跑一次)
sleep_count=$(mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'" -sN | awk '{print $2}')
if [ $sleep_count -gt 500 ]; then alert; fi

五、總結

層面動作效果
配置降低 wait_timeout 至 60-300s立竿見影清理殘留連線
程式碼禁用持久連線、確保顯式關閉、正確配置連線池源頭杜絕 Sleep 產生
架構引入 ProxySQL/MaxScale 連線多工、限流大規模微服務統一治理

「配置調優治標,程式碼規範治本」,雙管齊下才能徹底解決 Sleep 連線風暴。

copyright © 萬盛學電腦網 all rights reserved