MySQL主从复制报错13117?别慌,手把手教你排查和修复UUID冲突(附Docker环境实战)

凌晨三点,监控系统突然弹出一条告警:"MySQL从库复制中断,错误代码13117"。作为值班工程师的你瞬间清醒——生产环境的主从同步停了。别担心,这篇文章将带你像老司机一样,用20分钟彻底解决这个经典故障。我们会从报警分析开始,一步步拆解UUID冲突的来龙去脉,特别针对Docker环境给出完整解决方案,最后教你如何设置防护机制避免再次踩坑。

1. 紧急响应:快速定位问题根源

当主从复制中断时,第一要务是确认错误类型。连接从库执行:

SHOW SLAVE STATUS\G

在返回结果中,重点关注这两个字段:

  • Last_IO_Errno: 13117
  • Last_IO_Error: Fatal error: The replica I/O thread stops because source and replica have equal MySQL server UUIDs

这就是问题的明确指征——主从服务器的UUID相同导致复制线程中止。MySQL要求主从库必须拥有全局唯一的UUID,就像人的身份证号不能重复一样。

小知识:MySQL的server_uuid存储在数据目录的auto.cnf文件中,通常在首次启动服务时自动生成。格式类似:62570ab0-9260-11ed-a259-fa163efb5f25

2. 深度诊断:为什么会出现UUID冲突?

这种情况在以下场景特别常见:

  1. Docker环境:使用相同镜像启动多个MySQL容器时,如果数据卷未正确配置,会导致auto.cnf文件被复制
  2. 虚拟机克隆:基于模板快速部署MySQL实例时忘记重新生成UUID
  3. 备份恢复:直接将主库的数据文件完整拷贝到从库

验证UUID冲突的两种方法:

-- 方法1:SQL查询
SHOW VARIABLES LIKE 'server_uuid';

-- 方法2:检查数据文件
cat /var/lib/mysql/auto.cnf

在Docker环境中,需要先进入容器:

docker exec -it mysql_slave bash
cat /var/lib/mysql/auto.cnf

3. 精准修复:不同环境下的操作指南

3.1 Docker环境修复流程(重点)

这是最容易出错的场景,请严格按步骤操作:

  1. 停止从库容器(不影响主库)

    docker stop mysql_slave
    
  2. 备份原有auto.cnf文件

    docker exec mysql_slave mv /var/lib/mysql/auto.cnf /var/lib/mysql/auto.cnf.bak
    
  3. 关键步骤:确保数据卷持久化

    # 检查容器是否使用了独立数据卷
    docker inspect mysql_slave | grep Mounts
    
  4. 重启容器自动生成新UUID

    docker start mysql_slave
    
  5. 验证新UUID

    docker exec mysql_slave cat /var/lib/mysql/auto.cnf
    

3.2 物理机/虚拟机修复方案

  1. 停止从库MySQL服务

    systemctl stop mysqld
    
  2. 修改或删除auto.cnf

    mv /var/lib/mysql/auto.cnf /var/lib/mysql/auto.cnf.bak
    
  3. 启动服务生成新UUID

    systemctl start mysqld
    

4. 恢复验证与防护机制

修复后需要重新检查复制状态:

SHOW SLAVE STATUS\G

确认以下关键指标:

  • Slave_IO_Running: Yes
  • Slave_SQL_Running: Yes
  • Seconds_Behind_Master: 数值逐渐减小

预防措施

  1. 对于Docker部署,建议在docker-compose.yml中配置:

    volumes:
      - mysql_data:/var/lib/mysql
    
  2. 在MySQL配置文件中添加检测逻辑(my.cnf):

    [mysqld]
    server-id = 2  # 必须与主库不同
    
  3. 定期监控脚本示例:

    #!/bin/bash
    UUID_MASTER=$(mysql -h master -e "SHOW VARIABLES LIKE 'server_uuid'" | grep -v Value | awk '{print $2}')
    UUID_SLAVE=$(mysql -h slave -e "SHOW VARIABLES LIKE 'server_uuid'" | grep -v Value | awk '{print $2}')
    
    if [ "$UUID_MASTER" == "$UUID_SLAVE" ]; then
      echo "CRITICAL: UUID冲突检测到!" | mail -s "MySQL复制告警" admin@example.com
    fi
    

5. 深入原理:MySQL复制机制解析

理解这些底层原理能帮助你更好地排查问题:

复制线程工作流程

  1. I/O线程:连接主库,获取二进制日志(binlog)
  2. SQL线程:执行从I/O线程获取的事件

UUID的作用

  • 唯一标识MySQL实例
  • GTID(全局事务标识)的重要组成部分
  • 用于防止循环复制

常见错误对照表

错误代码含义解决方案
13117UUID冲突修改从库UUID
1236网络中断或权限问题检查网络和复制账户权限
1062主键冲突跳过错误或修复数据一致性

6. 高阶技巧:自动化运维方案

对于大规模部署,建议采用这些进阶方案:

  1. Terraform模板:在基础设施代码中确保每个MySQL实例有独立存储

    resource "docker_container" "mysql_slave" {
      name  = "mysql_slave"
      image = "mysql:8.0"
      volumes {
        container_path = "/var/lib/mysql"
        host_path      = "/data/mysql_slave"
      }
    }
    
  2. Ansible修复剧本

    - name: 修复MySQL UUID冲突
      hosts: mysql_slaves
      tasks:
        - name: 停止MySQL服务
          service:
            name: mysqld
            state: stopped
        
        - name: 备份auto.cnf
          command: mv /var/lib/mysql/auto.cnf /var/lib/mysql/auto.cnf.bak
          
        - name: 启动MySQL服务
          service:
            name: mysqld
            state: started
    
  3. Prometheus监控指标

    - name: mysql_slave_status
      rules:
        - alert: MySQLReplicationError
          expr: mysql_slave_status_slave_io_running == 0 or mysql_slave_status_slave_sql_running == 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "MySQL复制中断 (instance {{ $labels.instance }})"
            description: "错误代码: {{ $value }}"
    

记住,在Docker环境中处理MySQL问题时,数据持久化配置是关键中的关键。上周我们一个客户就因为在Kubernetes中忘记配置PV,导致容器重启后数据丢失,不得不从备份恢复。

更多推荐