我来为您编写一个使用pt-slave-restart监控多个从库的shell脚本,支持灵活的传参功能。
脚本代码
#!/bin/bash
# pt-slave-restart监控脚本
# 用于监控多个mysql从库的复制状态并在出错时自动重启
# 默认配置
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 [选项] [实例...]
选项:
-u, --user user mysql用户名 (默认: $default_user)
-p, --password pass mysql密码
-s, --socket socket 默认socket文件 (默认: $default_socket)
-h, --host host 主机名 (默认使用socket)
-p, --port port 端口号
-e, --errors errors 跳过的错误代码 (默认: $default_errors)
-m, --max-cycle cycle 最大重启循环次数 (默认: $default_max_cycle)
-s, --sleep seconds 检查间隔秒数 (默认: $default_sleep)
-l, --log file 日志文件 (默认: $default_log_file)
-c, --config file 配置文件 (默认: $config_file)
-d, --daemon 以守护进程模式运行
-v, --verbose 详细输出
--help 显示此帮助信息
实例格式:
host:port:socket:user:password
host:port
socket
别名 (需要在配置文件中定义)
配置文件格式 ($config_file):
# 每行定义一个mysql实例
# 格式: 别名|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
}
# 日志函数
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
}
# 解析实例参数
parse_instance() {
local instance=$1
local parsed_host parsed_port parsed_socket parsed_user parsed_password
# 重置为默认值
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" "无效的实例格式: $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" "未知的实例别名且不是有效的socket路径: $instance"
return 1
fi
fi
fi
host=$parsed_host
port=$parsed_port
socket=$parsed_socket
user=$parsed_user
password=$parsed_password
}
# 构建连接参数
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"
}
# 监控单个实例
monitor_instance() {
local instance_name=$1
local connect_args=$2
log "info" "开始监控实例: $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" "以守护进程模式启动: $pt_command"
eval $pt_command
else
log "info" "执行命令: $pt_command"
eval $pt_command
fi
local exit_code=$?
if [[ $exit_code -eq 0 ]]; then
log "info" "实例 $instance_name 监控启动成功"
else
log "error" "实例 $instance_name 监控启动失败,退出码: $exit_code"
fi
return $exit_code
}
# 主函数
main() {
# 设置默认值
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"
# 解析命令行参数
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 "未知选项: $1"
usage
exit 1
;;
*)
break
;;
esac
done
# 检查是否安装了pt-slave-restart
if ! command -v pt-slave-restart &> /dev/null; then
echo "错误: 未找到 pt-slave-restart 命令,请先安装 percona toolkit"
exit 1
fi
# 获取实例列表
if [[ $# -eq 0 ]]; then
# 如果没有提供实例参数,从配置文件读取所有实例
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 "错误: 配置文件中没有定义实例,且未提供实例参数"
usage
exit 1
fi
else
echo "错误: 未提供实例参数且配置文件不存在: $config_file"
usage
exit 1
fi
else
instances=("$@")
fi
log "info" "开始监控 ${#instances[@]} 个实例"
log "info" "跳过错误代码: $errors"
log "info" "最大重启循环: $max_cycle"
log "info" "检查间隔: $sleep 秒"
log "info" "日志文件: $log_file"
# 监控每个实例
for instance in "${instances[@]}"; do
# 保存原始值
original_host=$host
original_port=$port
original_socket=$socket
original_user=$user
original_password=$password
# 解析实例参数
if ! parse_instance "$instance"; then
log "error" "解析实例失败: $instance"
continue
fi
# 构建连接参数
connect_args=$(build_connection_args)
# 生成实例显示名称
if [[ -n "$socket" ]]; then
instance_name="socket:$socket"
elif [[ -n "$host" && -n "$port" ]]; then
instance_name="$host:$port"
else
instance_name="$instance"
fi
# 启动监控
monitor_instance "$instance_name" "$connect_args" &
# 恢复原始值
host=$original_host
port=$original_port
socket=$original_socket
user=$original_user
password=$original_password
done
# 如果不是守护进程模式,等待所有子进程
if [[ "$daemon" == "false" ]]; then
wait
else
log "info" "所有监控进程已在后台启动"
fi
}
# 运行主函数
main "$@"
配置文件示例
创建配置文件 /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. 基本用法
# 使用配置文件中的实例 ./pt-slave-monitor.sh slave1 slave2 # 直接指定实例 ./pt-slave-monitor.sh 192.168.1.101:3306 /tmp/mysql.sock
2. 指定连接参数
# 指定用户名和密码 ./pt-slave-monitor.sh -u monitor -p password123 slave1 slave2 # 指定错误代码和检查间隔 ./pt-slave-monitor.sh -e "1062,1032" -s 60 slave1
3. 守护进程模式
# 后台运行 ./pt-slave-monitor.sh -d -l /var/log/mysql-monitor.log slave1 slave2 slave3
4. 详细输出
# 显示详细日志 ./pt-slave-monitor.sh -v --errors "1062,1032,1205" slave1
脚本特点
- 灵活的实例定义:支持别名、host:port、socket等多种格式
- 配置文件支持:可以预定义实例配置
- 参数覆盖:命令行参数可以覆盖配置文件中的设置
- 错误处理:完善的错误处理和日志记录
- 守护进程模式:支持后台运行
- 多实例监控:同时监控多个从库实例
- 自定义错误代码:可配置需要跳过的复制错误
安装和使用步骤
- 保存脚本为
pt-slave-monitor.sh - 添加执行权限:
chmod +x pt-slave-monitor.sh - 创建配置文件(可选)
- 安装percona toolkit:
yum install percona-toolkit或apt-get install percona-toolkit - 运行脚本监控从库
这个脚本提供了灵活的配置选项和强大的监控功能,可以方便地管理多个mysql从库的复制状态监控。
以上就是linux使用pt-slave-restart监控多个从库的shell脚本案例的详细内容,更多关于linux t-slave-restart监控从库的资料请关注代码网其它相关文章!
发表评论