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

Linux Shell 腳本定時清理 MySQL Locked 進程

     編輯:MySQL 綜合教學

場景背景

線上 MySQL 因架構設計不合理、長事務、未提交事務等原因,頻繁出現 Locked 狀態進程堆積,導致正常業務請求阻塞、甚至資料庫不可用。臨時方案:編寫 Shell 腳本定時掃描並 Kill 這些進程,緩解癥狀,賏時間進行架構優化。

腳本完整代碼

#!/bin/bash
# mysql_kill_locked.sh
# 定時清理 MySQL Locked 狀態進程
# 使用方式:加入 crontab,如每分鐘執行 */1 * * * * /path/mysql_kill_locked.sh

# ========== 配置區 ==========
MYSQL_PWD="your_root_password"           # MySQL root 密碼
MYSQL_EXEC="/usr/local/mysql/bin/mysql"  # mysql 客戶端路徑
TMP_DIR="/tmp"
FILE_SH="$TMP_DIR/mysql_kill_locked.sh"  # 生成的 kill 腳本
FILE_TMP="$TMP_DIR/mysql_kill_locked.tmp" # 臨時進程列表
FILE_LOG="$TMP_DIR/mysql_kill_locked.log" # 執行日志
# ============================

# 1. 獲取所有 Locked 進程 ID
$MYSQL_EXEC -uroot -p$MYSQL_PWD -e "SHOW PROCESSLIST" | grep -i "Locked" > $FILE_TMP

# 2. 記錄日志
cat $FILE_TMP >> $FILE_LOG

# 3. 生成 kill 命令腳本
for line in $(cat $FILE_TMP | awk '{print $1}'); do
    echo "$MYSQL_EXEC -uroot -p$MYSQL_PWD -e \"KILL $line\"" >> $FILE_SH
done

# 4. 執行 kill
chmod +x $FILE_SH
sh $FILE_SH

# 5. 清理臨時文件
> $FILE_SH
# 可選:保留日志最近 7 天
find $TMP_DIR -name "mysql_kill_locked.log" -mtime +7 -delete

腳本邏輯解析

  1. SHOW PROCESSLIST:獲取當前所有線程狀態
  2. grep -i "Locked":篩選 State 列包含 Locked 的行(不區分大小寫)
  3. awk '{print $1}':提取第一列 Id(線程 ID)
  4. 生成 KILL 命令:每個 ID 生成一條 KILL <id> 命令
  5. 批量執行:將命令寫入臨時腳本並執行

部署與驗證

1. 授權執行權限

chmod +x /path/mysql_kill_locked.sh

2. 手動測試

/path/mysql_kill_locked.sh
cat /tmp/mysql_kill_locked.log  # 查看是否有 Locked 進程被記錄

3. 加入 crontab 定時執行

crontab -e
# 每 30 秒執行一次(需兩條配合)
* * * * * /path/mysql_kill_locked.sh
* * * * * sleep 30 && /path/mysql_kill_locked.sh

# 或每分鐘執行
*/1 * * * * /path/mysql_kill_locked.sh

進階優化版(推薦生產使用)

#!/bin/bash
# 優化版:增加鎖等待時間閾值、白名單、告警

MYSQL_PWD="xxx"
MYSQL_EXEC="/usr/local/mysql/bin/mysql"
LOG_FILE="/var/log/mysql_kill_locked.log"
WHITELIST="12345 67890"  # 不要 kill 的線程 ID(如備份線程)
THRESHOLD=30             # 超過 30 秒才 kill

# 獲取進程詳細信息
PROC_INFO=$($MYSQL_EXEC -uroot -p$MYSQL_PWD -e "SHOW FULL PROCESSLIST\G")

echo "$PROC_INFO" | awk -v thresh="$THRESHOLD" -v wl="$WHITELIST" '
BEGIN {
    split(wl, white, " ")
    for (i in white) whitelist[white[i]] = 1
}
/^Id:/ {id=$2}
/^Time:/ {time=$2}
/^State:/ {state=$0; sub(/^State: /, "", state)}
/^Info:/ {info=$0; sub(/^Info: /, "", info)}
/^$/ {
    if (state ~ /Locked/ && time > thresh && !(id in whitelist)) {
        print "KILL " id "; -- " info
    }
}' | while read kill_cmd; do
    echo "$(date) $kill_cmd" >> $LOG_FILE
    $MYSQL_EXEC -uroot -p$MYSQL_PWD -e "$kill_cmd"
done

根治方案提醒

⚠️ 腳本只是止痛藥,不是治本藥

長期依賴 Kill 進程會導致:

  • 事務回滾產生大量 Undo Log,影響性能
  • 數據一致性風險(非事務性操作被打斷)
  • 掩蓋真實問題:慢查詢、缺索引、長事務、鎖競爭、死鎖

必須同步進行:

  1. 開啟慢查詢日志,分析 TOP SQL
  2. SHOW ENGINE INNODB STATUS 分析鎖等待鏈
  3. 優化大事務:拆分、縮短持有時間
  4. 補充缺失索引
  5. 調整隔離級別(RC 減少 Gap Lock)
  6. 架構層面:讀寫分離、分庫分表、引入緩存

總結

Shell 定時 Kill Locked 進程是應對 MySQL 阻塞的應急手段。腳本核心是 SHOW PROCESSLIST | grep Locked | awk '{print $1}' | xargs -I {} mysql -e 'KILL {}'。生產環境請使用優化版(帶閾值、白名單、日志),並務必同步推進根治優化。

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