一、为什么我们需要主从复制自动修复脚本

搞数据库的朋友都知道,MySQL主从复制是个好东西,它能帮我们实现读写分离、数据备份、负载均衡等各种花活。但问题是,这个复制链路特别娇气,动不动就给你来个"Slave_SQL_Running: No",让人头疼得很。

想象一下,半夜三点突然收到报警,主从复制断了。你从被窝里爬起来,睡眼惺忪地连上服务器,开始手动修复。这种场景是不是很熟悉?要是能有个自动修复的脚本,那该多好啊!

二、主从复制中断的常见原因

在动手写脚本之前,咱们得先搞清楚复制中断的常见原因。根据我这些年踩过的坑,主要有这么几种情况:

  1. 主库和从库数据不一致导致的1062错误(主键冲突)
  2. 从库上找不到要删除的记录导致的1032错误
  3. 网络闪断导致的连接中断
  4. 主库的binlog被purge掉了
  5. 从库的relay log损坏

三、自动修复脚本的设计思路

我们的自动修复脚本要能智能判断中断原因,然后对症下药。这里我用Shell脚本来实现,因为它简单直接,在Linux环境下运行良好。

基本思路是这样的:

  1. 定期检查复制状态
  2. 发现异常后记录错误信息
  3. 根据错误类型选择修复策略
  4. 尝试自动修复
  5. 修复失败时发送告警

四、具体实现代码示例

下面是一个完整的Shell脚本实现,我加了详细注释:

#!/bin/bash
# MySQL主从复制自动修复脚本
# 技术栈:Shell + MySQL Client

# 配置部分
MYSQL_USER="repl_user"
MYSQL_PASS="repl_password"
MYSQL_PORT=3306
ALERT_EMAIL="admin@example.com"
LOG_FILE="/var/log/mysql_repl_repair.log"

# 记录日志函数
function log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}

# 发送邮件告警函数
function send_alert() {
    echo "$1" | mail -s "MySQL复制告警" $ALERT_EMAIL
    log "已发送告警邮件: $1"
}

# 检查复制状态函数
function check_replication() {
    # 获取复制状态信息
    STATUS=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW SLAVE STATUS\G")
    
    # 检查Slave_IO和Slave_SQL线程是否运行
    IO_RUNNING=$(echo "$STATUS" | grep "Slave_IO_Running:" | awk '{print $2}')
    SQL_RUNNING=$(echo "$STATUS" | grep "Slave_SQL_Running:" | awk '{print $2}')
    LAST_ERROR=$(echo "$STATUS" | grep "Last_Error:" | awk -F': ' '{print $2}')
    
    if [ "$IO_RUNNING" != "Yes" ] || [ "$SQL_RUNNING" != "Yes" ]; then
        log "复制中断! IO状态: $IO_RUNNING, SQL状态: $SQL_RUNNING, 错误信息: $LAST_ERROR"
        handle_error "$LAST_ERROR"
    else
        log "复制状态正常"
    fi
}

# 错误处理函数
function handle_error() {
    local error_msg=$1
    
    # 处理主键冲突错误(1062)
    if [[ $error_msg =~ "1062" ]]; then
        log "检测到主键冲突错误,尝试跳过该事务"
        mysql -u$MYSQL_USER -p$MYSQL_PASS -e "STOP SLAVE; SET GLOBAL sql_slave_skip_counter = 1; START SLAVE;"
        log "已跳过错误事务,重启复制"
        
    # 处理记录不存在错误(1032)    
    elif [[ $error_msg =~ "1032" ]]; then
        log "检测到记录不存在错误,尝试跳过该事务"
        mysql -u$MYSQL_USER -p$MYSQL_PASS -e "STOP SLAVE; SET GLOBAL sql_slave_skip_counter = 1; START SLAVE;"
        log "已跳过错误事务,重启复制"
        
    # 处理其他错误
    else
        log "未知错误类型,需要人工干预"
        send_alert "MySQL复制遇到未知错误: $error_msg"
    fi
    
    # 再次检查状态
    sleep 5
    check_replication
}

# 主循环
while true; do
    check_replication
    sleep 60  # 每分钟检查一次
done

五、脚本的进阶优化

上面的基础版本已经能处理常见问题了,但我们可以做得更好。下面是几个优化方向:

  1. 增加重试机制:不是所有错误都能一次修复成功
  2. 添加白名单机制:某些表可以忽略复制错误
  3. 实现自动数据修复:对于可以确定的数据不一致,自动修复数据
  4. 集成监控系统:与Prometheus、Zabbix等监控系统对接

这里给出一个带重试机制的优化版本:

# 在handle_error函数中添加重试逻辑
function handle_error() {
    local error_msg=$1
    local retry_count=0
    local max_retry=3
    
    while [ $retry_count -lt $max_retry ]; do
        # 同上错误处理逻辑...
        
        # 检查是否修复成功
        STATUS=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW SLAVE STATUS\G")
        IO_RUNNING=$(echo "$STATUS" | grep "Slave_IO_Running:" | awk '{print $2}')
        SQL_RUNNING=$(echo "$STATUS" | grep "Slave_SQL_Running:" | awk '{print $2}')
        
        if [ "$IO_RUNNING" == "Yes" ] && [ "$SQL_RUNNING" == "Yes" ]; then
            log "修复成功!"
            return 0
        fi
        
        ((retry_count++))
        log "修复失败,正在重试($retry_count/$max_retry)..."
        sleep 5
    done
    
    log "修复失败,达到最大重试次数"
    send_alert "MySQL复制自动修复失败,请人工干预。错误信息: $error_msg"
}

六、应用场景分析

这个脚本特别适合以下场景:

  1. 电商大促期间:数据库压力大,复制容易中断,人工修复来不及
  2. 夜间维护时段:没人值班时自动处理问题
  3. 分布式系统:有大量MySQL实例需要管理
  4. 微服务架构:每个服务有自己的数据库,复制关系复杂

七、技术优缺点

优点:

  1. 自动化程度高,减少人工干预
  2. 响应速度快,问题发现及时
  3. 可定制性强,能适应各种业务场景
  4. 实现成本低,Shell脚本随处可用

缺点:

  1. 无法处理所有错误类型,复杂问题仍需人工
  2. 跳过事务可能导致数据不一致
  3. 需要谨慎配置,错误的修复策略可能雪上加霜

八、注意事项

在使用这个脚本时,有几点要特别注意:

  1. 权限控制:脚本使用的数据库账号要有足够权限但不要给太高
  2. 日志轮转:记得配置logrotate,避免日志文件过大
  3. 监控告警:不能完全依赖脚本,还要有备用监控手段
  4. 测试验证:在生产环境使用前,一定要在测试环境充分验证
  5. 定期审查:随着业务变化,要定期审查和更新修复策略

九、总结

MySQL主从复制是个好东西,但也是个"玻璃心"。通过这个自动修复脚本,我们能够解决80%的常见复制中断问题,大大减轻DBA的工作负担。虽然它不能包治百病,但确实是个实用的"急救包"。

记住,自动化不是万能的,但没有自动化是万万不能的。这个脚本可以作为一个起点,你可以根据自己的业务特点进行扩展和优化。比如增加微信告警、对接K8s环境、支持多实例管理等。

最后提醒一句,任何自动化工具都要谨慎使用,特别是在处理数据问题时。在实现自动化的同时,一定要保留足够的人工干预通道和回滚机制。