Linux使用pt-slave-restart監(jiān)控多個(gè)從庫的Shell腳本案例
我來為您編寫一個(gè)使用pt-slave-restart監(jiān)控多個(gè)從庫的Shell腳本,支持靈活的傳參功能。
腳本代碼
#!/bin/bash
# pt-slave-restart監(jiān)控腳本
# 用于監(jiān)控多個(gè)MySQL從庫的復(fù)制狀態(tài)并在出錯(cuò)時(shí)自動(dòng)重啟
# 默認(rèn)配置
DEFAULT_USER="monitor_user"
DEFAULT_SOCKET="/tmp/mysql.sock"
DEFAULT_ERRORS="1062,1032,1205,1158,1159,1007,1008,1050,1051,1054,1060,1061,1094,1213,1169,1232"
DEFAULT_MAX_CYCLE=10
DEFAULT_SLEEP=300
DEFAULT_LOG_FILE="/var/log/pt-slave-restart.log"
CONFIG_FILE="/etc/pt-slave-restart.conf"
# 顯示用法
usage() {
cat << EOF
用法: $0 [選項(xiàng)] [實(shí)例...]
選項(xiàng):
-u, --user USER MySQL用戶名 (默認(rèn): $DEFAULT_USER)
-p, --password PASS MySQL密碼
-S, --socket SOCKET 默認(rèn)socket文件 (默認(rèn): $DEFAULT_SOCKET)
-h, --host HOST 主機(jī)名 (默認(rèn)使用socket)
-P, --port PORT 端口號(hào)
-e, --errors ERRORS 跳過的錯(cuò)誤代碼 (默認(rèn): $DEFAULT_ERRORS)
-m, --max-cycle CYCLE 最大重啟循環(huán)次數(shù) (默認(rèn): $DEFAULT_MAX_CYCLE)
-s, --sleep SECONDS 檢查間隔秒數(shù) (默認(rèn): $DEFAULT_SLEEP)
-l, --log FILE 日志文件 (默認(rèn): $DEFAULT_LOG_FILE)
-c, --config FILE 配置文件 (默認(rèn): $CONFIG_FILE)
-d, --daemon 以守護(hù)進(jìn)程模式運(yùn)行
-v, --verbose 詳細(xì)輸出
--help 顯示此幫助信息
實(shí)例格式:
host:port:socket:user:password
host:port
socket
別名 (需要在配置文件中定義)
配置文件格式 ($CONFIG_FILE):
# 每行定義一個(gè)MySQL實(shí)例
# 格式: 別名|host:port|user|password|socket
slave1|192.168.1.101:3306|monitor|password123|/tmp/mysql1.sock
slave2|192.168.1.102:3307|monitor|password123|/tmp/mysql2.sock
slave3||monitor|password123|/tmp/mysql3.sock
示例:
$0 -u monitor -p pass123 slave1 slave2
$0 -d -s 60 192.168.1.101:3306 /tmp/mysql.sock
$0 --verbose --errors "1062,1032" slave1
EOF
}
# 日志函數(shù)
log() {
local level=$1
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
if [[ "$VERBOSE" == "true" && "$level" != "DEBUG" ]]; then
echo "[$timestamp] [$level] $message"
fi
}
# 讀取配置文件
read_config() {
local alias=$1
if [[ -f "$CONFIG_FILE" ]]; then
while IFS='|' read -r config_alias config_host_port config_user config_password config_socket; do
if [[ "$config_alias" == "$alias" ]]; then
HOST=${config_host_port%:*}
PORT=${config_host_port#*:}
USER=$config_user
PASSWORD=$config_password
SOCKET=$config_socket
return 0
fi
done < <(grep -v '^#' "$CONFIG_FILE" | grep -v '^$')
fi
return 1
}
# 解析實(shí)例參數(shù)
parse_instance() {
local instance=$1
local parsed_host parsed_port parsed_socket parsed_user parsed_password
# 重置為默認(rèn)值
parsed_host=$HOST
parsed_port=$PORT
parsed_socket=$SOCKET
parsed_user=$USER
parsed_password=$PASSWORD
# 檢查是否是配置文件中定義的別名
if read_config "$instance"; then
return 0
fi
# 解析 host:port:socket:user:password 格式
if [[ "$instance" =~ : ]]; then
IFS=':' read -r -a parts <<< "$instance"
case ${#parts[@]} in
2)
parsed_host=${parts[0]}
parsed_port=${parts[1]}
parsed_socket=""
;;
3)
parsed_host=${parts[0]}
parsed_port=${parts[1]}
parsed_socket=${parts[2]}
;;
4)
parsed_host=${parts[0]}
parsed_port=${parts[1]}
parsed_socket=${parts[2]}
parsed_user=${parts[3]}
;;
5)
parsed_host=${parts[0]}
parsed_port=${parts[1]}
parsed_socket=${parts[2]}
parsed_user=${parts[3]}
parsed_password=${parts[4]}
;;
*)
log "ERROR" "無效的實(shí)例格式: $instance"
return 1
;;
esac
else
# 如果只提供socket路徑
if [[ "$instance" =~ \.sock ]]; then
parsed_socket=$instance
parsed_host=""
parsed_port=""
else
# 嘗試作為別名從配置文件中讀取
if ! read_config "$instance"; then
log "ERROR" "未知的實(shí)例別名且不是有效的socket路徑: $instance"
return 1
fi
fi
fi
HOST=$parsed_host
PORT=$parsed_port
SOCKET=$parsed_socket
USER=$parsed_user
PASSWORD=$parsed_password
}
# 構(gòu)建連接參數(shù)
build_connection_args() {
local connect_args=""
if [[ -n "$SOCKET" ]]; then
connect_args="--socket=$SOCKET"
elif [[ -n "$HOST" && -n "$PORT" ]]; then
connect_args="--host=$HOST --port=$PORT"
elif [[ -n "$HOST" ]]; then
connect_args="--host=$HOST"
if [[ -n "$PORT" ]]; then
connect_args="$connect_args --port=$PORT"
fi
else
connect_args="--socket=$DEFAULT_SOCKET"
fi
if [[ -n "$USER" ]]; then
connect_args="$connect_args --user=$USER"
fi
if [[ -n "$PASSWORD" ]]; then
connect_args="$connect_args --password=$PASSWORD"
fi
echo "$connect_args"
}
# 監(jiān)控單個(gè)實(shí)例
monitor_instance() {
local instance_name=$1
local connect_args=$2
log "INFO" "開始監(jiān)控實(shí)例: $instance_name"
local pt_command="pt-slave-restart $connect_args"
pt_command="$pt_command --error-numbers=$ERRORS"
pt_command="$pt_command --max-cycle=$MAX_CYCLE"
pt_command="$pt_command --sleep=$SLEEP"
pt_command="$pt_command --log=$LOG_FILE"
pt_command="$pt_command --verbose"
pt_command="$pt_command --skip-count=0"
pt_command="$pt_command --always"
if [[ "$DAEMON" == "true" ]]; then
pt_command="$pt_command --daemonize"
log "INFO" "以守護(hù)進(jìn)程模式啟動(dòng): $pt_command"
eval $pt_command
else
log "INFO" "執(zhí)行命令: $pt_command"
eval $pt_command
fi
local exit_code=$?
if [[ $exit_code -eq 0 ]]; then
log "INFO" "實(shí)例 $instance_name 監(jiān)控啟動(dòng)成功"
else
log "ERROR" "實(shí)例 $instance_name 監(jiān)控啟動(dòng)失敗,退出碼: $exit_code"
fi
return $exit_code
}
# 主函數(shù)
main() {
# 設(shè)置默認(rèn)值
USER=$DEFAULT_USER
SOCKET=$DEFAULT_SOCKET
ERRORS=$DEFAULT_ERRORS
MAX_CYCLE=$DEFAULT_MAX_CYCLE
SLEEP=$DEFAULT_SLEEP
LOG_FILE=$DEFAULT_LOG_FILE
DAEMON="false"
VERBOSE="false"
# 解析命令行參數(shù)
while [[ $# -gt 0 ]]; do
case $1 in
-u|--user)
USER="$2"
shift 2
;;
-p|--password)
PASSWORD="$2"
shift 2
;;
-S|--socket)
SOCKET="$2"
shift 2
;;
-h|--host)
HOST="$2"
shift 2
;;
-P|--port)
PORT="$2"
shift 2
;;
-e|--errors)
ERRORS="$2"
shift 2
;;
-m|--max-cycle)
MAX_CYCLE="$2"
shift 2
;;
-s|--sleep)
SLEEP="$2"
shift 2
;;
-l|--log)
LOG_FILE="$2"
shift 2
;;
-c|--config)
CONFIG_FILE="$2"
shift 2
;;
-d|--daemon)
DAEMON="true"
shift
;;
-v|--verbose)
VERBOSE="true"
shift
;;
--help)
usage
exit 0
;;
-*)
echo "未知選項(xiàng): $1"
usage
exit 1
;;
*)
break
;;
esac
done
# 檢查是否安裝了pt-slave-restart
if ! command -v pt-slave-restart &> /dev/null; then
echo "錯(cuò)誤: 未找到 pt-slave-restart 命令,請(qǐng)先安裝 Percona Toolkit"
exit 1
fi
# 獲取實(shí)例列表
if [[ $# -eq 0 ]]; then
# 如果沒有提供實(shí)例參數(shù),從配置文件讀取所有實(shí)例
if [[ -f "$CONFIG_FILE" ]]; then
instances=()
while IFS='|' read -r alias host_port user password socket; do
if [[ -n "$alias" && ! "$alias" =~ ^# ]]; then
instances+=("$alias")
fi
done < <(grep -v '^#' "$CONFIG_FILE" | grep -v '^$')
if [[ ${#instances[@]} -eq 0 ]]; then
echo "錯(cuò)誤: 配置文件中沒有定義實(shí)例,且未提供實(shí)例參數(shù)"
usage
exit 1
fi
else
echo "錯(cuò)誤: 未提供實(shí)例參數(shù)且配置文件不存在: $CONFIG_FILE"
usage
exit 1
fi
else
instances=("$@")
fi
log "INFO" "開始監(jiān)控 ${#instances[@]} 個(gè)實(shí)例"
log "INFO" "跳過錯(cuò)誤代碼: $ERRORS"
log "INFO" "最大重啟循環(huán): $MAX_CYCLE"
log "INFO" "檢查間隔: $SLEEP 秒"
log "INFO" "日志文件: $LOG_FILE"
# 監(jiān)控每個(gè)實(shí)例
for instance in "${instances[@]}"; do
# 保存原始值
original_host=$HOST
original_port=$PORT
original_socket=$SOCKET
original_user=$USER
original_password=$PASSWORD
# 解析實(shí)例參數(shù)
if ! parse_instance "$instance"; then
log "ERROR" "解析實(shí)例失敗: $instance"
continue
fi
# 構(gòu)建連接參數(shù)
connect_args=$(build_connection_args)
# 生成實(shí)例顯示名稱
if [[ -n "$SOCKET" ]]; then
instance_name="socket:$SOCKET"
elif [[ -n "$HOST" && -n "$PORT" ]]; then
instance_name="$HOST:$PORT"
else
instance_name="$instance"
fi
# 啟動(dòng)監(jiān)控
monitor_instance "$instance_name" "$connect_args" &
# 恢復(fù)原始值
HOST=$original_host
PORT=$original_port
SOCKET=$original_socket
USER=$original_user
PASSWORD=$original_password
done
# 如果不是守護(hù)進(jìn)程模式,等待所有子進(jìn)程
if [[ "$DAEMON" == "false" ]]; then
wait
else
log "INFO" "所有監(jiān)控進(jìn)程已在后臺(tái)啟動(dòng)"
fi
}
# 運(yùn)行主函數(shù)
main "$@"
配置文件示例
創(chuàng)建配置文件 /etc/pt-slave-restart.conf:
# 格式: 別名|host:port|user|password|socket slave1|192.168.1.101:3306|monitor|password123|/tmp/mysql1.sock slave2|192.168.1.102:3307|monitor|password123|/tmp/mysql2.sock slave3||monitor|password123|/tmp/mysql3.sock slave4|192.168.1.104:3306|monitor|password123|
使用示例
1. 基本用法
# 使用配置文件中的實(shí)例 ./pt-slave-monitor.sh slave1 slave2 # 直接指定實(shí)例 ./pt-slave-monitor.sh 192.168.1.101:3306 /tmp/mysql.sock
2. 指定連接參數(shù)
# 指定用戶名和密碼 ./pt-slave-monitor.sh -u monitor -p password123 slave1 slave2 # 指定錯(cuò)誤代碼和檢查間隔 ./pt-slave-monitor.sh -e "1062,1032" -s 60 slave1
3. 守護(hù)進(jìn)程模式
# 后臺(tái)運(yùn)行 ./pt-slave-monitor.sh -d -l /var/log/mysql-monitor.log slave1 slave2 slave3
4. 詳細(xì)輸出
# 顯示詳細(xì)日志 ./pt-slave-monitor.sh -v --errors "1062,1032,1205" slave1
腳本特點(diǎn)
- 靈活的實(shí)例定義:支持別名、host:port、socket等多種格式
- 配置文件支持:可以預(yù)定義實(shí)例配置
- 參數(shù)覆蓋:命令行參數(shù)可以覆蓋配置文件中的設(shè)置
- 錯(cuò)誤處理:完善的錯(cuò)誤處理和日志記錄
- 守護(hù)進(jìn)程模式:支持后臺(tái)運(yùn)行
- 多實(shí)例監(jiān)控:同時(shí)監(jiān)控多個(gè)從庫實(shí)例
- 自定義錯(cuò)誤代碼:可配置需要跳過的復(fù)制錯(cuò)誤
安裝和使用步驟
- 保存腳本為
pt-slave-monitor.sh - 添加執(zhí)行權(quán)限:
chmod +x pt-slave-monitor.sh - 創(chuàng)建配置文件(可選)
- 安裝Percona Toolkit:
yum install percona-toolkit或apt-get install percona-toolkit - 運(yùn)行腳本監(jiān)控從庫
這個(gè)腳本提供了靈活的配置選項(xiàng)和強(qiáng)大的監(jiān)控功能,可以方便地管理多個(gè)MySQL從庫的復(fù)制狀態(tài)監(jiān)控。
以上就是Linux使用pt-slave-restart監(jiān)控多個(gè)從庫的Shell腳本案例的詳細(xì)內(nèi)容,更多關(guān)于Linux t-slave-restart監(jiān)控從庫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Ubuntu上使用Netdata設(shè)置實(shí)時(shí)性能監(jiān)控的詳細(xì)流程
Netdata通過可擴(kuò)展的Web儀表板提供準(zhǔn)確的性能監(jiān)控,可以顯示Linux系統(tǒng)上的流程和服務(wù)。這篇文章給大家介紹Ubuntu上使用Netdata設(shè)置實(shí)時(shí)性能監(jiān)控的流程,感興趣的朋友一起看看吧2018-08-08
Linux設(shè)置虛擬內(nèi)存的教學(xué)與實(shí)戰(zhàn)教程
這篇文章主要給大家介紹了關(guān)于Linux設(shè)置虛擬內(nèi)存教學(xué)與實(shí)戰(zhàn)的相關(guān)資料,文中通過示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
服務(wù)器安裝寶塔面板無法遠(yuǎn)程連接數(shù)據(jù)庫的解決方法
這篇文章主要介紹了服務(wù)器安裝寶塔面板無法遠(yuǎn)程連接數(shù)據(jù)庫的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
如何對(duì)安裝Linux的服務(wù)器進(jìn)行緩存清除
這篇文章主要介紹了如何對(duì)安裝Linux的服務(wù)器進(jìn)行緩存清除問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11

