开发者

Linux使用pt-slave-restart监控多个从库的Shell脚本案例

目录
  • 脚本代码
  • 配置文件示例
  • 使用示例
    • 1. 基本用法
    • 2. 指定连接参数
    • 3. 守护进程模式
    • 4. 详细输出
  • 脚本特点
    • 安装和使用步骤

      我来为您编写一个使用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.androidconf"
      
      # 显示用法
      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
          别名 (需要在配置文件中定义)
      
      php配置文件格式 ($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
           www.devze.com           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
                      ;;
      php            -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-slaandroidve-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
      

      脚本特点

      1. 灵活的实例定义:支持别名、host:port、socket等多种格式
      2. 配置文件支持:可以预定义实例配置
      3. 参数覆盖:命令行参数可以覆盖配置文件中的设置
      4. 错误处理:完善的错误处理和日志记录
      5. 守护进程模式:支持后台运行
      6. 多实例监控:同时监控多个从库实例
      7. 自定义错误代码:可配置需要跳过的复制错误

      安装和使用步骤

      1. 保存脚本为 pt-slave-monitor.sh
      2. 添加执行权限:chmod +x pt-slave-monitor.sh
      3. 创建配置文件(可选)
      4. 安装Percona Toolkit:yum install percona-toolkit 或 apt-get install percona-toolkit
      5. 运行脚本监控从库

      这个脚本提供了灵活的配置选项和强大的监控功能,可以方便地管理多个MySQL从库的复制状态监控。

      以上就是linux使用pt-slave-restart监控多个从库的Shell脚本案例的详细内容,更多关于Linux t-slave-restart监控从库的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新运维

      运维排行榜