一、为什么我们需要主从复制自动修复脚本
搞数据库的朋友都知道,MySQL主从复制是个好东西,它能帮我们实现读写分离、数据备份、负载均衡等各种花活。但问题是,这个复制链路特别娇气,动不动就给你来个"Slave_SQL_Running: No",让人头疼得很。
想象一下,半夜三点突然收到报警,主从复制断了。你从被窝里爬起来,睡眼惺忪地连上服务器,开始手动修复。这种场景是不是很熟悉?要是能有个自动修复的脚本,那该多好啊!
二、主从复制中断的常见原因
在动手写脚本之前,咱们得先搞清楚复制中断的常见原因。根据我这些年踩过的坑,主要有这么几种情况:
- 主库和从库数据不一致导致的1062错误(主键冲突)
- 从库上找不到要删除的记录导致的1032错误
- 网络闪断导致的连接中断
- 主库的binlog被purge掉了
- 从库的relay log损坏
三、自动修复脚本的设计思路
我们的自动修复脚本要能智能判断中断原因,然后对症下药。这里我用Shell脚本来实现,因为它简单直接,在Linux环境下运行良好。
基本思路是这样的:
- 定期检查复制状态
- 发现异常后记录错误信息
- 根据错误类型选择修复策略
- 尝试自动修复
- 修复失败时发送告警
四、具体实现代码示例
下面是一个完整的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
五、脚本的进阶优化
上面的基础版本已经能处理常见问题了,但我们可以做得更好。下面是几个优化方向:
- 增加重试机制:不是所有错误都能一次修复成功
- 添加白名单机制:某些表可以忽略复制错误
- 实现自动数据修复:对于可以确定的数据不一致,自动修复数据
- 集成监控系统:与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"
}
六、应用场景分析
这个脚本特别适合以下场景:
- 电商大促期间:数据库压力大,复制容易中断,人工修复来不及
- 夜间维护时段:没人值班时自动处理问题
- 分布式系统:有大量MySQL实例需要管理
- 微服务架构:每个服务有自己的数据库,复制关系复杂
七、技术优缺点
优点:
- 自动化程度高,减少人工干预
- 响应速度快,问题发现及时
- 可定制性强,能适应各种业务场景
- 实现成本低,Shell脚本随处可用
缺点:
- 无法处理所有错误类型,复杂问题仍需人工
- 跳过事务可能导致数据不一致
- 需要谨慎配置,错误的修复策略可能雪上加霜
八、注意事项
在使用这个脚本时,有几点要特别注意:
- 权限控制:脚本使用的数据库账号要有足够权限但不要给太高
- 日志轮转:记得配置logrotate,避免日志文件过大
- 监控告警:不能完全依赖脚本,还要有备用监控手段
- 测试验证:在生产环境使用前,一定要在测试环境充分验证
- 定期审查:随着业务变化,要定期审查和更新修复策略
九、总结
MySQL主从复制是个好东西,但也是个"玻璃心"。通过这个自动修复脚本,我们能够解决80%的常见复制中断问题,大大减轻DBA的工作负担。虽然它不能包治百病,但确实是个实用的"急救包"。
记住,自动化不是万能的,但没有自动化是万万不能的。这个脚本可以作为一个起点,你可以根据自己的业务特点进行扩展和优化。比如增加微信告警、对接K8s环境、支持多实例管理等。
最后提醒一句,任何自动化工具都要谨慎使用,特别是在处理数据问题时。在实现自动化的同时,一定要保留足够的人工干预通道和回滚机制。
评论