找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1871

积分

0

好友

259

主题
发表于 2025-12-25 18:12:37 | 查看: 32| 回复: 0

此脚本是专门用于MySQL8.0数据库主从复制架构下(基于GTID的复制)的自动切换的脚本,配置好相关基本信息(通用用户名,密码,主从数据库的复制用户,用户密码,IP地址,端口号)后,直接手动执行shell脚本即可完成MySQL主从架构下的自动切换功能,是计划内的数据库切换演练有利便捷的执行工具,可大大减少人工切换产生的误操作和切换时间问题。

脚本内容

该脚本名称为 mysql_switchover.sh

#!/bin/bash
# =============================================================================
# 基于GTID的MySQL 8.0 一主一从架构主从切换脚本 (支持不同端口)
# 版本: 1.0
# 修复内容: 表头输出问题、错误处理机制、GTID一致性检查逻辑
# =============================================================================
# >>>>>>>>>>>> 第一部分:脚本配置区域 (使用前请务必修改) <<<<<<<<<<<<
# 数据库连接凭证
MYSQL_USER="repluser"
MYSQL_PASS="repluser"

# 当前主从节点IP地址及端口
CURRENT_MASTER_HOST="10.2.8.4"
CURRENT_MASTER_PORT="3306"
CURRENT_SLAVE_HOST="10.2.8.4"
CURRENT_SLAVE_PORT="3307"

# 日志文件
LOG_FILE="/var/log/mysql_switchover.log"
LOCK_FILE="/tmp/mysql_switchover.lock"

# 连接超时时间(秒)
MYSQL_CONNECT_TIMEOUT=5

# >>>>>>>>>>>> 第二部分:核心函数定义 <<<<<<<<<<<<
# 日志记录函数
log() {
    local LEVEL=$1
    local MSG=$2
    local TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
    echo "[$TIMESTAMP] [$LEVEL] $MSG" | tee -a "$LOG_FILE"
}

# 错误处理与退出函数
error_exit() {
    local MSG=$1
    log "ERROR" "$MSG"
    [ -f "$LOCK_FILE" ] && rm -f "$LOCK_FILE"
    exit 1
}

# 通用的MySQL连接执行函数
mysql_exec() {
    local HOST=$1
    local PORT=$2
    local SQL=$3
    mysql -h"$HOST" -P"$PORT" -u"$MYSQL_USER" -p"$MYSQL_PASS" --connect-timeout=$MYSQL_CONNECT_TIMEOUT -e "$SQL" 2>/dev/null
}

# 获取MySQL单值结果 (专门用于获取单个值的函数)
get_mysql_value() {
    local HOST=$1
    local PORT=$2
    local SQL=$3
    mysql -h"$HOST" -P"$PORT" -u"$MYSQL_USER" -p"$MYSQL_PASS" --connect-timeout=$MYSQL_CONNECT_TIMEOUT -N -s -e "$SQL" 2>/dev/null | tail -1
}

# 检查MySQL实例是否可连接
check_mysql_connectivity() {
    local HOST=$1
    local PORT=$2
    if mysql_exec "$HOST" "$PORT" "SELECT 1;" &> /dev/null; then
        log "INFO" "成功连接到MySQL实例: $HOST:$PORT"
        return 0
    else
        log "ERROR" "无法连接到MySQL实例: $HOST:$PORT"
        return 1
    fi
}

# 创建锁文件防止脚本重复运行
create_lockfile() {
    if [ -f "$LOCK_FILE" ]; then
        local LOCK_PID=$(cat "$LOCK_FILE")
        if ps -p "$LOCK_PID" > /dev/null 2>&1; then
            log "ERROR" "脚本已在运行中 (PID: $LOCK_PID),请勿重复执行"
            exit 1
        else
            log "WARNING" "发现残留锁文件,清理后继续"
            rm -f "$LOCK_FILE"
        fi
    fi
    echo $$ > "$LOCK_FILE"
}

# 清理锁文件
cleanup_lockfile() {
    [ -f "$LOCK_FILE" ] && rm -f "$LOCK_FILE"
}

# 检查复制延迟并等待追平(基于SHOW REPLICA STATUS)
wait_for_replica_catchup() {
    local REPLICA_HOST=$1
    local REPLICA_PORT=$2
    local MAX_DELAY=60
    local WAIT_TIMEOUT=300
    local WAIT_STEP=5
    local TOTAL_WAIT=0

    log "INFO" "检查副本延迟并等待追平,最大容忍延迟: ${MAX_DELAY}秒,超时: ${WAIT_TIMEOUT}秒"

    while [ $TOTAL_WAIT -lt $WAIT_TIMEOUT ]; do
        # 修正:从SHOW REPLICA STATUS获取Seconds_Behind_Source值
        local REPLICA_STATUS=$(mysql_exec "$REPLICA_HOST" "$REPLICA_PORT" "SHOW REPLICA STATUS\\G")
        local DELAY=$(echo "$REPLICA_STATUS" | grep -i "Seconds_Behind_Source:" | awk '{print $2}')

        # 处理空值和NULL情况
        if [ "$DELAY" == "NULL" ] || [ -z "$DELAY" ]; then
            log "ERROR" "无法获取副本延迟信息或复制已停止"
            return 1
        fi

        # 确保DELAY是数字
        if ! [[ "$DELAY" =~ ^[0-9]+$ ]]; then
            log "ERROR" "获取的延迟值非数字: $DELAY"
            return 1
        fi

        if [ "$DELAY" -eq 0 ]; then
            log "INFO" "副本已完全追平,延迟: 0秒"
            return 0
        elif [ "$DELAY" -le $MAX_DELAY ]; then
            log "INFO" "副本当前延迟: ${DELAY}秒,在容忍范围内"
            break
        else
            log "INFO" "副本当前延迟: ${DELAY}秒,等待追平... 已等待 ${TOTAL_WAIT}秒"
            sleep $WAIT_STEP
            TOTAL_WAIT=$((TOTAL_WAIT + WAIT_STEP))
        fi
    done

    if [ $TOTAL_WAIT -ge $WAIT_TIMEOUT ]; then
        log "WARNING" "等待副本追平超时,当前延迟: ${DELAY}秒"
        return 2
    fi
    return 0
}

# 检查复制状态 (使用MySQL 8.0的REPLICA语法)
check_replica_status() {
    local HOST=$1
    local PORT=$2
    local STATUS=$(mysql_exec "$HOST" "$PORT" "SHOW REPLICA STATUS\\G")
    if [ -z "$STATUS" ]; then
        log "WARNING" "未找到复制状态信息,主机可能不是副本角色: $HOST:$PORT"
        return 2
    fi

    local IO_THREAD=$(echo "$STATUS" | grep -i "Replica_IO_Running:" | awk '{print $2}')
    local SQL_THREAD=$(echo "$STATUS" | grep -i "Replica_SQL_Running:" | awk '{print $2}')
    local SECONDS_BEHIND=$(echo "$STATUS" | grep -i "Seconds_Behind_Source:" | awk '{print $2}')

    if [[ "$IO_THREAD" == "Yes" ]] && [[ "$SQL_THREAD" == "Yes" ]]; then
        log "INFO" "副本复制线程运行正常: $HOST:$PORT, 延迟: ${SECONDS_BEHIND:-N/A} 秒"
        return 0
    else
        log "ERROR" "副本复制线程异常 - IO线程: $IO_THREAD, SQL线程: $SQL_THREAD"
        return 1
    fi
}

# 检查主从数据一致性 (基于GTID)
check_gtid_consistency() {
    local MASTER_HOST=$1
    local MASTER_PORT=$2
    local SLAVE_HOST=$3
    local SLAVE_PORT=$4

    log "INFO" "开始检查主从GTID一致性..."

    MASTER_GTID_SET=$(get_mysql_value "$MASTER_HOST" "$MASTER_PORT" "SELECT @@GLOBAL.GTID_EXECUTED;")
    SLAVE_GTID_SET=$(get_mysql_value "$SLAVE_HOST" "$SLAVE_PORT" "SELECT @@GLOBAL.GTID_EXECUTED;")

    if [ -z "$MASTER_GTID_SET" ] || [ -z "$SLAVE_GTID_SET" ]; then
        log "ERROR" "获取主库或从库的GTID_EXECUTED失败"
        return 1
    fi

    # 使用GTID_SUBTRACT函数检查从库是否缺失事务
    local GTID_DIFF=$(get_mysql_value "$SLAVE_HOST" "$SLAVE_PORT" "SELECT GTID_SUBTRACT('$MASTER_GTID_SET', '$SLAVE_GTID_SET') AS DIFF;")
    if [ -n "$GTID_DIFF" ] && [ "$GTID_DIFF" != "" ]; then
        log "WARNING" "主从数据存在GTID差异: $GTID_DIFF"
        return 2
    else
        log "INFO" "主从GTID一致性检查通过"
        return 0
    fi
}

# 设置实例为只读模式
set_read_only() {
    local HOST=$1
    local PORT=$2
    local MODE=$3

    if [ "$MODE" == "on" ]; then
        log "INFO" "设置实例为只读模式: $HOST:$PORT"
        mysql_exec "$HOST" "$PORT" "SET GLOBAL super_read_only=1, read_only=1;"

        # 修复:使用改进的连接数查询,避免表头问题
        local WRITE_CONNS=$(get_mysql_value "$HOST" "$PORT" "SELECT COUNT(*) FROM performance_schema.processlist where command not in ('Sleep','Binlog Dump','Binlog Dump GTID') AND USER NOT IN ('system user','event_scheduler') AND id <> connection_id();")
        # 修复:添加数值检查,避免非数字值比较
        if [ "$WRITE_CONNS" -gt 0 ] 2>/dev/null; then
            log "WARNING" "发现 $WRITE_CONNS 个活跃写连接,建议处理"
        else
            log "INFO" "无活跃写连接或获取连接数失败"
        fi
    else
        log "INFO" "关闭实例只读模式: $HOST:$PORT"
        mysql_exec "$HOST" "$PORT" "SET GLOBAL read_only=0, super_read_only=0;"
    fi
}

# 停止并重置复制
stop_and_reset_replica() {
    local HOST=$1
    local PORT=$2
    log "INFO" "在主机上停止并重置复制: $HOST:$PORT"
    mysql_exec "$HOST" "$PORT" "STOP REPLICA;"
    mysql_exec "$HOST" "$PORT" "RESET REPLICA ALL;"
    if [ $? -eq 0 ]; then
        log "INFO" "成功停止并重置复制: $HOST:$PORT"
        return 0
    else
        log "ERROR" "停止或重置复制操作失败: $HOST:$PORT"
        return 1
    fi
}

# 提升从库为新主库
promote_replica_to_source() {
    local REPLICA_HOST=$1
    local REPLICA_PORT=$2
    log "INFO" "开始提升副本为新主库: $REPLICA_HOST:$REPLICA_PORT"
    # 确保复制已停止并重置
    stop_and_reset_replica "$REPLICA_HOST" "$REPLICA_PORT" || return 1
    # 关闭只读模式,使其可写
    set_read_only "$REPLICA_HOST" "$REPLICA_PORT" "off"
    log "INFO" "副本提升为新主库操作完成: $REPLICA_HOST:$REPLICA_PORT"
}

# 配置旧主库作为新主库的从库
setup_old_source_as_replica() {
    local OLD_MASTER_HOST=$1
    local OLD_MASTER_PORT=$2
    local NEW_MASTER_HOST=$3
    local NEW_MASTER_PORT=$4

    log "INFO" "开始配置旧主库作为新主库的副本: $OLD_MASTER_HOST:$OLD_MASTER_PORT -> $NEW_MASTER_HOST:$NEW_MASTER_PORT"

    # 检查旧主库连接
    check_mysql_connectivity "$OLD_MASTER_HOST" "$OLD_MASTER_PORT" || return 1

    # 停止并重置复制(如果之前是主库)
    stop_and_reset_replica "$OLD_MASTER_HOST" "$OLD_MASTER_PORT"

    # 使用GTID自动定位配置主从复制
    mysql_exec "$OLD_MASTER_HOST" "$OLD_MASTER_PORT" "CHANGE REPLICATION SOURCE TO SOURCE_HOST='$NEW_MASTER_HOST',SOURCE_PORT=$NEW_MASTER_PORT,SOURCE_USER='$MYSQL_USER',SOURCE_PASSWORD='$MYSQL_PASS',SOURCE_AUTO_POSITION=1,GET_SOURCE_PUBLIC_KEY=1; START REPLICA;"

    if [ $? -eq 0 ]; then
        log "INFO" "成功在旧主库上配置指向新主库的复制"
        # 短暂等待后检查复制状态
        sleep 5
        if check_replica_status "$OLD_MASTER_HOST" "$OLD_MASTER_PORT"; then
            log "INFO" "旧主库到新主库的复制状态正常"
            return 0
        else
            log "WARNING" "旧主库到新主库的复制状态异常"
            return 2
        fi
    else
        log "ERROR" "在旧主库上配置复制关系失败"
        return 1
    fi
}

# 切换后验证函数 - 完全重写版
verify_switchover_result() {
    local NEW_SOURCE_HOST=$1
    local NEW_SOURCE_PORT=$2
    local OLD_SOURCE_HOST=$3
    local OLD_SOURCE_PORT=$4

    log "INFO" "开始验证切换结果..."
    # 创建临时测试数据库(使用更安全的命名)
    local TEST_DB="test_switchover_$(date +%s)"

    # 第一层验证:创建数据库
    local CREATE_DB_SQL="CREATE DATABASE IF NOT EXISTS $TEST_DB"
    if ! mysql_exec "$NEW_SOURCE_HOST" "$NEW_SOURCE_PORT" "$CREATE_DB_SQL"; then
        log "ERROR" "新主库创建数据库测试失败: $NEW_SOURCE_HOST:$NEW_SOURCE_PORT"
        return 1
    fi
    log "INFO" "新主库创建数据库测试通过: $NEW_SOURCE_HOST:$NEW_SOURCE_PORT"

    # 第二层验证:创建表
    # 对于复杂的SQL,使用heredoc最安全
    local CREATE_TABLE_SQL=$(cat <<SQL
CREATE TABLE $TEST_DB.verify_switchover (id INT PRIMARY KEY, test_time TIMESTAMP)
SQL
)
    if ! mysql_exec "$NEW_SOURCE_HOST" "$NEW_SOURCE_PORT" "$CREATE_TABLE_SQL"; then
        log "ERROR" "新主库创建表测试失败"
        mysql_exec "$NEW_SOURCE_HOST" "$NEW_SOURCE_PORT" "DROP DATABASE IF EXISTS $TEST_DB"
        return 1
    fi

    # 第三层验证:插入数据
    local INSERT_SQL=$(cat <<SQL
INSERT INTO $TEST_DB.verify_switchover VALUES (1, NOW())
SQL
)
    if ! mysql_exec "$NEW_SOURCE_HOST" "$NEW_SOURCE_PORT" "$INSERT_SQL"; then
        log "ERROR" "新主库插入数据测试失败"
        mysql_exec "$NEW_SOURCE_HOST" "$NEW_SOURCE_PORT" "DROP DATABASE IF EXISTS $TEST_DB"
        return 1
    fi
    log "INFO" "新主库写测试完全通过: $NEW_SOURCE_HOST:$NEW_SOURCE_PORT"

    # 清理测试数据
    mysql_exec "$NEW_SOURCE_HOST" "$NEW_SOURCE_PORT" "DROP DATABASE IF EXISTS $TEST_DB"

    # 验证旧主库复制状态
    if check_mysql_connectivity "$OLD_SOURCE_HOST" "$OLD_SOURCE_PORT"; then
        sleep 3
        if check_replica_status "$OLD_SOURCE_HOST" "$OLD_SOURCE_PORT"; then
            log "INFO" "旧主库到新主库的复制状态正常"
        else
            log "WARNING" "旧主库到新主库的复制状态异常,需人工检查"
            return 2
        fi
    else
        log "INFO" "旧主库当前不可达,复制状态略过检查"
    fi
    log "INFO" "切换验证完成"
    return 0
}

# >>>>>>>>>>>> 第三部分:切换主流程 <<<<<<<<<<<<
# 切换函数
switchover() {
    log "INFO" "开始主从切换流程..."

    # 1. 前置检查
    log "INFO" "步骤1: 执行前置检查"
    check_mysql_connectivity "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" || error_exit "原主库无法连接,切换中止"
    check_mysql_connectivity "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT" || error_exit "从库无法连接,切换中止"
    check_replica_status "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT" || error_exit "从库复制状态异常,切换中止"

    # 2. 检查数据一致性
    log "INFO" "步骤2: 检查主从数据一致性"
    check_gtid_consistency "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT"
    local CONSISTENCY_RESULT=$?
    if [ $CONSISTENCY_RESULT -eq 1 ]; then
        error_exit "GTID一致性检查失败,切换中止"
    elif [ $CONSISTENCY_RESULT -eq 2 ]; then
        log "WARNING" "主从数据存在差异,请确认是否继续切换? (y/N)"
        read -t 30 user_input
        if [[ ! "$user_input" =~ ^[Yy]$ ]]; then
            log "INFO" "用户取消切换操作"
            exit 1
        fi
        log "INFO" "用户确认继续切换"
    fi

    # 3. 设置原主库为只读
    log "INFO" "步骤3: 设置原主库为只读模式"
    set_read_only "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" "on"

    # 4. 等待从库追平延迟
    log "INFO" "步骤4: 检查从库复制延迟"
    wait_for_replica_catchup "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT"
    local CATCHUP_RESULT=$?
    if [ $CATCHUP_RESULT -eq 1 ]; then
        error_exit "检查副本延迟时发生错误"
    elif [ $CATCHUP_RESULT -eq 2 ]; then
        log "WARNING" "从库延迟较大,请确认是否继续切换? (y/N)"
        read -t 30 user_input
        if [[ ! "$user_input" =~ ^[Yy]$ ]]; then
            # 恢复原主库可写状态
            set_read_only "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" "off"
            log "INFO" "用户取消切换操作,已恢复原主库写权限"
            exit 1
        fi
        log "INFO" "用户确认继续切换"
    fi

    # 5. 提升从库为新主库
    log "INFO" "步骤5: 提升从库为新主库"
    promote_replica_to_source "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT" || error_exit "提升从库失败"

    # 6. 配置旧主库为新从库(加强错误处理)
    log "INFO" "步骤6: 配置旧主库为新从库"
    if ! setup_old_source_as_replica "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT"; then
        log "WARNING" "配置旧主库为新从库失败,尝试备用方案..."
        # 备用方案:重置GTID并重试
        local NEW_MASTER_GTID=$(get_mysql_value "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT" "SELECT @@GLOBAL.GTID_EXECUTED;")
        if [ -n "$NEW_MASTER_GTID" ]; then
            log "INFO" "尝试备用GTID同步方案"
            mysql_exec "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" "STOP REPLICA; RESET REPLICA ALL;"
            mysql_exec "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" "SET GLOBAL gtid_purged='$NEW_MASTER_GTID';"
            if setup_old_source_as_replica "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT" "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT"; then
                log "INFO" "备用方案配置成功"
            else
                log "ERROR" "备用方案也失败,需要手动干预"
                return 2
            fi
        else
            log "ERROR" "无法获取新主库GTID,备用方案无法执行"
            return 2
        fi
    fi

    # 7. 最终验证(必须成功)
    log "INFO" "步骤7: 执行切换后验证"
    if verify_switchover_result "$CURRENT_SLAVE_HOST" "$CURRENT_SLAVE_PORT" "$CURRENT_MASTER_HOST" "$CURRENT_MASTER_PORT"; then
        log "INFO" "切换验证通过"
    else
        error_exit "切换验证失败,新主库可能不可用"
    fi

    log "INFO" "主从切换流程全部完成!新主库: $CURRENT_SLAVE_HOST:$CURRENT_SLAVE_PORT"
}

# >>>>>>>>>>>> 第四部分:脚本入口 <<<<<<<<<<<<
# 主执行逻辑
main() {
    # 创建锁文件
    create_lockfile
    trap cleanup_lockfile EXIT

    log "INFO" "==== MySQL主从切换脚本开始执行 ===="
    log "INFO" "原主库: $CURRENT_MASTER_HOST:$CURRENT_MASTER_PORT"
    log "INFO" "原从库: $CURRENT_SLAVE_HOST:$CURRENT_SLAVE_PORT"

    switchover
    local result=$?

    if [ $result -eq 0 ]; then
        log "INFO" "脚本执行成功"
    else
        log "ERROR" "脚本执行过程中遇到错误"
    fi

    log "INFO" "==== MySQL主从切换脚本执行结束 ===="
    exit $result
}

# 脚本执行入口
main

重点说明

  1. 版本限制(MySQL8.0.23及以上)
    该脚本测试时使用的MySQL版本为8.0.41,主从架构搭建时是采用新的 CHANGE REPLICATION SOURCE TO 语法创建的,在脚本获取相关信息时也是采用 SHOW REPLICA STATUS\G方式获取,由于新的语法是官方从8.0.23版本才进行调整的,故本脚本限制的版本必须是大于等于MySQL8.0.23。

  2. 复制限制(GTID模式)
    脚本中测试环境复制架构采用的是基于GTID的复制方式,故如果主从架构是基于binlog+position的老方式复制是不适用的。

  3. 额外说明
    在使用该脚本前,需要对脚本中的开始位置(第一部分:脚本配置区域)进行提前配置好,根据实际环境(复制用户,IP地址,端口,日志路径)进行相关配置才可以运行。

使用方法

  1. 保存脚本并赋权
    chmod +x mysql_switchover.sh
  2. 手工执行脚本
    ./mysql_switchover.sh
  3. 执行过程:
    [root@VM-8-4-opencloudos ~]# ./mysql_switchover.sh
    [2025-11-28 17:22:27] [INFO] ==== MySQL主从切换脚本开始执行 ====
    [2025-11-28 17:22:27] [INFO] 原主库: 10.2.8.4:3306
    [2025-11-28 17:22:27] [INFO] 原从库: 10.2.8.4:3307
    [2025-11-28 17:22:27] [INFO] 开始主从切换流程...
    [2025-11-28 17:22:27] [INFO] 步骤1: 执行前置检查
    [2025-11-28 17:22:27] [INFO] 成功连接到MySQL实例: 10.2.8.4:3306
    [2025-11-28 17:22:27] [INFO] 成功连接到MySQL实例: 10.2.8.4:3307
    [2025-11-28 17:22:27] [INFO] 副本复制线程运行正常: 10.2.8.4:3307, 延迟: 0 秒
    [2025-11-28 17:22:27] [INFO] 步骤2: 检查主从数据一致性
    [2025-11-28 17:22:27] [INFO] 开始检查主从GTID一致性...
    [2025-11-28 17:22:27] [INFO] 主从GTID一致性检查通过
    [2025-11-28 17:22:27] [INFO] 步骤3: 设置原主库为只读模式
    [2025-11-28 17:22:27] [INFO] 设置实例为只读模式: 10.2.8.4:3306
    [2025-11-28 17:22:28] [INFO] 无活跃写连接或获取连接数失败
    [2025-11-28 17:22:28] [INFO] 步骤4: 检查从库复制延迟
    [2025-11-28 17:22:28] [INFO] 检查副本延迟并等待追平,最大容忍延迟: 60秒,超时: 300秒
    [2025-11-28 17:22:28] [INFO] 副本已完全追平,延迟: 0秒
    [2025-11-28 17:22:28] [INFO] 步骤5: 提升从库为新主库
    [2025-11-28 17:22:28] [INFO] 开始提升副本为新主库: 10.2.8.4:3307
    [2025-11-28 17:22:28] [INFO] 在主机上停止并重置复制: 10.2.8.4:3307
    [2025-11-28 17:22:28] [INFO] 成功停止并重置复制: 10.2.8.4:3307
    [2025-11-28 17:22:28] [INFO] 关闭实例只读模式: 10.2.8.4:3307
    [2025-11-28 17:22:28] [INFO] 副本提升为新主库操作完成: 10.2.8.4:3307
    [2025-11-28 17:22:28] [INFO] 步骤6: 配置旧主库为新从库
    [2025-11-28 17:22:28] [INFO] 开始配置旧主库作为新主库的副本: 10.2.8.4:3306 -> 10.2.8.4:3307
    [2025-11-28 17:22:29] [INFO] 成功连接到MySQL实例: 10.2.8.4:3306
    [2025-11-28 17:22:29] [INFO] 在主机上停止并重置复制: 10.2.8.4:3306
    [2025-11-28 17:22:29] [INFO] 成功停止并重置复制: 10.2.8.4:3306
    [2025-11-28 17:22:30] [INFO] 成功在旧主库上配置指向新主库的复制
    [2025-11-28 17:22:36] [INFO] 副本复制线程运行正常: 10.2.8.4:3306, 延迟: 0 秒
    [2025-11-28 17:22:36] [INFO] 旧主库到新主库的复制状态正常
    [2025-11-28 17:22:36] [INFO] 步骤7: 执行切换后验证
    [2025-11-28 17:22:36] [INFO] 开始验证切换结果...
    [2025-11-28 17:22:36] [INFO] 新主库创建数据库测试通过: 10.2.8.4:3307
    [2025-11-28 17:22:39] [INFO] 新主库写测试完全通过: 10.2.8.4:3307
    [2025-11-28 17:22:40] [INFO] 成功连接到MySQL实例: 10.2.8.4:3306
    [2025-11-28 17:22:44] [INFO] 副本复制线程运行正常: 10.2.8.4:3306, 延迟: 0 秒
    [2025-11-28 17:22:44] [INFO] 旧主库到新主库的复制状态正常
    [2025-11-28 17:22:44] [INFO] 切换验证完成
    [2025-11-28 17:22:44] [INFO] 切换验证通过
    [2025-11-28 17:22:44] [INFO] 主从切换流程全部完成!新主库: 10.2.8.4:3307
    [2025-11-28 17:22:44] [INFO] 脚本执行成功
    [2025-11-28 17:22:44] [INFO] ==== MySQL主从切换脚本执行结束 ====
    [root@VM-8-4-opencloudos ~]#

    说明:本示例测试环境为:

    • MySQL主库:10.2.8.4 端口为 3306
    • MySQL从库:10.2.8.4 端口为 3307
    • 复制用户:repluser。 本示例中复制用户赋权为所有权限,实际用户可根据情况更换,但必须有相关权限才行(设置参数read_only,复制权限replication slave,建库,建表,增删改查数据,表和库)

示例截图:
示例执行结果截图

总结

此脚本根据实际环境进行参数配置后,可以自动化的进行针对Shell主从环境的切换演练,并可以适当的通过脚本中内容进行调整,比如可以自定义设置从库延迟的时间,是否可以接受从库延迟等方式。通过反复测试可以正常运行,基本可以替代手工切换过程中的状态检查和繁琐的确认环节,从而有效减少人为失误。




上一篇:Android16原生截图机制解析:为何多数厂商选择拼接方案?
下一篇:Ubuntu 22.04手动初始化PostgreSQL 14数据库实例指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-10 18:34 , Processed in 0.232058 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表