Files
agent-skills/skills/g3fo-docs/references/middleware/mysql/fault-analysis.md
T
ken.li e798751e4b docs(nacos-config): 添加 nacos_config 目录分析与修改指南
新增 g3fo-nacos-config 目录下的 SKILL.md 文档,详细说明 nacos_config 目录的结构、用户交互流程及配置文件的添加与修改规则。新增 yml-placement.md 文件,提供常见顶级键的插入顺序,以保持配置文件风格一致。
2026-02-09 17:25:13 +08:00

12 KiB
Raw Blame History

MySQL 8.4 复制冲突解决指南

AI 响应规范 (MySQL 执行策略):

  1. 强制参数: 所有 docker exec 命令必须包含 -h127.0.0.1 参数。
  2. 双重输出: 涉及 SQL 操作时,必须同时输出 Docker 执行命令 和 纯 SQL 脚本。
  3. 默认连接: 默认使用 -uroot -pafe123456 -h127.0.0.1。
  4. 排障连贯性: 诊断复制冲突时,在提供 A. 查看复制状态概要 后,必须紧跟 提供 B. 自动提取错误详情 脚本,以便用户直接获取修复建议。

1. 复制冲突解决(主键/唯一键重复或记录缺失)

1.1 快速定位冲突信息

当复制中断时,必须按顺序执行以下两步:首先查看概要,然后提取详细错误以获取修复脚本。

A. 查看复制状态概要:

# 方式 1: 传统状态查看 (重点关注 Last_SQL_Error)
docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "SHOW REPLICA STATUS\G" | grep -E "Replica_.*_Running|Last_SQL_Error|Retrieved_Gtid_Set|Executed_Gtid_Set"

# 方式 2: 多线程环境下查看详情 (若启用并行复制,SHOW REPLICA STATUS 只能看到协调线程错误)
docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "SELECT * FROM performance_schema.replication_applier_status_by_worker WHERE LAST_ERROR_NUMBER > 0\G"

B. 自动提取错误详情(支持 1062 重复键 / 1032 记录未找到): 直接在宿主机执行以下脚本,它会自动解析错误日志并生成对应的修复方案:

# 提取冲突 GTID、表、冲突值及修复建议
grep -aE "Duplicate entry|Error_code: 1032" /data/mysql/logs/mysql_error.log | perl -nle '
if (/^(\S+).*?transaction\s+[\x27"]([^\x27"]+)[\x27"].*?table\s+([^\s;]+);/) {
  my ($time, $gtid, $table) = ($1, $2, $3);
  print "\n" . "="x60;
  print "时间: $time";
  print "GTID: $gtid";
  print "表名: $table";

  if (/Duplicate entry\s+[\x27"]([^\x27"]+)[\x27"]\s+for\s+key\s+[\x27"]([^\x27"]+)[\x27"]/) {
    print "类型: 1062 (主键/唯一键重复)";
    print "冲突值: $1 (索引: $2)";
    print "\n方案 A (手动修复 - 删除从库冲突行):";
    print "DELETE FROM $table WHERE [主键列] = \x27$1\x27;";
    print "\n方案 B (跳过事务 - 保持从库现状):";
    print "STOP REPLICA; SET GTID_NEXT=\x27$gtid\x27; BEGIN; COMMIT; SET GTID_NEXT=\x27AUTOMATIC\x27; START REPLICA;";
  } elsif (/Error_code: 1032|HA_ERR_KEY_NOT_FOUND/) {
    print "类型: 1032 (记录未找到 - 通常是 Delete/Update 目标不存在)";
    print "说明: 目标行在从库已不存在,Delete 操作已实质生效。";
    print "\n方案 A (直接跳过 - 安全):";
    print "STOP REPLICA; SET GTID_NEXT=\x27$gtid\x27; BEGIN; COMMIT; SET GTID_NEXT=\x27AUTOMATIC\x27; START REPLICA;";
  }
}
'

1.2 安全修复冲突(推荐删除冲突数据)

停止复制,临时关闭 binlog(避免删除操作同步到对端):

A. Docker 执行模式 (包含 -h127.0.0.1):

# 以实际冲突表和主键为例(示例:test_sync.t1 的 id=12)
docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "
STOP REPLICA;
SET sql_log_bin = OFF;
DELETE FROM `test_sync`.`t1` WHERE `id` = 12;
SET sql_log_bin = ON;
START REPLICA;
SHOW REPLICA STATUS\G;
"

B. 纯 SQL 模式:

STOP REPLICA;
SET sql_log_bin = OFF;
DELETE FROM `test_sync`.`t1` WHERE `id` = 12;
SET sql_log_bin = ON;
START REPLICA;
SHOW REPLICA STATUS\G;

1.3 应急跳过冲突事务(仅紧急场景)

精准跳过指定 GTID 事务(MySQL 8.0+ 推荐):

A. Docker 执行模式 (包含 -h127.0.0.1):

docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "
STOP REPLICA;
SET GTID_NEXT = '760f0600-f896-11ef-b265-0242ac130002:6';  # 替换为实际冲突 GTID
BEGIN; COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START REPLICA;
"

B. 纯 SQL 模式:

STOP REPLICA;
SET GTID_NEXT = '760f0600-f896-11ef-b265-0242ac130002:6';
BEGIN; COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START REPLICA;

2. 全量备份还原解决冲突(适用于严重冲突场景)

当复制冲突过多、数据不一致严重,或手动修复成本过高时,可以使用全量备份还原的方式彻底解决冲突问题。此方法通过从主库(或备份库)全量备份数据,然后在从库上完全还原,实现数据一致性。

2.1 相关脚本

2.2 操作流程

步骤 1: 在备份机上执行备份

在需要备份的 MySQL 服务器(通常是主库或数据一致的节点)上执行备份脚本:

# 备份所有数据库(默认)
cd /data/backup/mysql
./backup-sync.sh

# 或指定标签备份
./backup-sync.sh -t conflict_resolve

# 或备份指定数据库
./backup-sync.sh database1 database2

备份脚本会自动:

  • 设置 MySQL 为只读模式
  • 停止复制(如果是从库)
  • 记录当前 GTID 位置
  • 执行全量备份并压缩为 .7z 文件
  • 恢复 MySQL 为读写模式

备份完成后,会在 /data/backup/mysql/ 目录下生成 YYYYMMDDHHMMSS.7z 或 YYYYMMDDHHMMSS_TAG.7z 格式的备份文件。

步骤 2: 传输备份文件到还原机

使用 scp 将备份文件推送到需要还原的 DB 机的 /data/backup/mysql/ 目录:

# 从备份机执行(将备份文件推送到还原机)
scp /data/backup/mysql/YYYYMMDDHHMMSS.7z user@restore-server:/data/backup/mysql/

# 示例
scp /data/backup/mysql/20250127120000.7z root@192.168.1.100:/data/backup/mysql/

注意: 确保还原机的 /data/backup/mysql/ 目录存在且有写入权限。

步骤 3: 在还原机上还原前准备(清空数据并重启 MySQL)

在需要还原的 MySQL 服务器(还原机)上,先清空数据目录并重启容器,再执行还原脚本,避免旧数据与备份冲突。

  1. 删除数据目录中的现有数据(在还原机执行):
# 删除 /data/mysql/data 下数据(请确认该路径为当前 MySQL 数据目录)
rm -rf /data/mysql/data/*
  1. 在 docker-compose 目录下重启 MySQL 容器(在还原机执行):
cd /data/docker-compose
docker-compose down mysql
docker-compose up -d mysql

等待 MySQL 启动就绪(可查看容器日志或稍等 10~30 秒)后,再进行步骤 4 的还原。

步骤 4: 在还原机上执行还原脚本

在还原机上执行还原脚本:

cd /data/backup/mysql

# 还原所有数据库
./restore-sync.sh YYYYMMDDHHMMSS.7z

# 或仅还原指定数据库
./restore-sync.sh YYYYMMDDHHMMSS.7z database1.sql

还原脚本会自动:

  • 设置 MySQL 为只读模式
  • 停止复制
  • 重置二进制日志和 GTID
  • 导入备份数据(导入时禁用 binlog,避免循环复制)
  • 设置 GTID purged(从备份时的 GTID 位置)
  • 恢复 MySQL 为读写模式

步骤 5: 还原后创建账号(在还原机执行)

还原完成后,在还原机上创建复制与业务所需账号(若备份中已含用户则可酌情跳过,建议按环境统一执行一次)。

A. 创建复制账号 repl 与日志刷新账号 log_flush

Docker 执行:

docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "
CREATE USER 'repl'@'%' IDENTIFIED BY 'afe123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
"

docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "
CREATE USER 'log_flush'@'127.0.0.1' IDENTIFIED BY 'afe123456';
GRANT RELOAD ON *.* TO 'log_flush'@'127.0.0.1';
FLUSH PRIVILEGES;
"

B. 创建 G3SF 相关业务账号

Docker 执行:

docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "
CREATE USER 'g3sf'@'%' IDENTIFIED BY 'k2-fkW@7z>zSYQo';
GRANT ALL PRIVILEGES ON *.* TO 'g3sf'@'%';
CREATE USER 'g3sfreader'@'%' IDENTIFIED BY '@feg3sf10port';
GRANT SELECT ON *.* TO 'g3sfreader'@'%';
CREATE USER 'g3sfsupport'@'%' IDENTIFIED BY '@feg3sf10port';
GRANT ALL PRIVILEGES ON *.* TO 'g3sfsupport'@'%';
FLUSH PRIVILEGES;
"

纯 SQL(在 MySQL 客户端中执行):

-- g3sf:应用库完全访问
CREATE USER 'g3sf'@'%' IDENTIFIED BY 'k2-fkW@7z>zSYQo';
GRANT ALL PRIVILEGES ON *.* TO 'g3sf'@'%';
-- g3sfreader:只读
CREATE USER 'g3sfreader'@'%' IDENTIFIED BY '@feg3sf10port';
GRANT SELECT ON *.* TO 'g3sfreader'@'%';
-- g3sfsupport:支持库完全访问
CREATE USER 'g3sfsupport'@'%' IDENTIFIED BY '@feg3sf10port';
GRANT ALL PRIVILEGES ON *.* TO 'g3sfsupport'@'%';
FLUSH PRIVILEGES;

步骤 6: 在还原机上连接主 DB 并启动复制(在还原机执行)

在还原机上配置复制源为主库(将 NODE_A_IP 替换为实际主 DB 的 IP):

A. Docker 执行模式 (包含 -h127.0.0.1):

# 将 NODE_A_IP 替换为主 DB 的 IP
docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "
STOP REPLICA;
RESET REPLICA ALL;
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST = 'NODE_A_IP',
  SOURCE_PORT = 3306,
  SOURCE_USER = 'repl',
  SOURCE_PASSWORD = 'afe123456',
  SOURCE_AUTO_POSITION = 1,
  SOURCE_CONNECT_RETRY = 10,
  SOURCE_RETRY_COUNT = 9999999999,
  GET_SOURCE_PUBLIC_KEY = 1;
START REPLICA;
"

B. 纯 SQL 模式:

STOP REPLICA;
RESET REPLICA ALL;
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST = 'NODE_A_IP',   -- 主 DB IP
  SOURCE_PORT = 3306,
  SOURCE_USER = 'repl',
  SOURCE_PASSWORD = 'afe123456',
  SOURCE_AUTO_POSITION = 1,
  SOURCE_CONNECT_RETRY = 10,
  SOURCE_RETRY_COUNT = 9999999999,
  GET_SOURCE_PUBLIC_KEY = 1;
START REPLICA;

等待几秒后检查复制状态,确认 IO/SQL 均为 Yes:

sleep 5
docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "SHOW REPLICA STATUS\G"

检查关键指标:

  • Replica_IO_Running: 应为 Yes
  • Replica_SQL_Running: 应为 Yes
  • Last_IO_Error / Last_SQL_Error: 应为空

状态正常后,再进行步骤 7,在主库上配置指向本机(还原机/备份库)。

步骤 7: 在主库上配置指向备份库(还原机)并检查状态(在主库执行)

在**主备份数据库(主库)**上配置复制源为当前还原机(备份库),将 NODE_B_IP 替换为还原机/备份 DB 的 IP:

A. Docker 执行模式 (包含 -h127.0.0.1):

# 将 NODE_B_IP 替换为备份 DB(还原机)的 IP
docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "
STOP REPLICA;
RESET REPLICA ALL;
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST = 'NODE_B_IP',
  SOURCE_PORT = 3306,
  SOURCE_USER = 'repl',
  SOURCE_PASSWORD = 'afe123456',
  SOURCE_AUTO_POSITION = 1,
  SOURCE_CONNECT_RETRY = 10,
  SOURCE_RETRY_COUNT = 9999999999,
  GET_SOURCE_PUBLIC_KEY = 1;
START REPLICA;
"

B. 纯 SQL 模式:

STOP REPLICA;
RESET REPLICA ALL;
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST = 'NODE_B_IP',   -- 备份 DB(还原机)IP
  SOURCE_PORT = 3306,
  SOURCE_USER = 'repl',
  SOURCE_PASSWORD = 'afe123456',
  SOURCE_AUTO_POSITION = 1,
  SOURCE_CONNECT_RETRY = 10,
  SOURCE_RETRY_COUNT = 9999999999,
  GET_SOURCE_PUBLIC_KEY = 1;
START REPLICA;

等待几秒后再次检查主库复制状态:

sleep 5
docker exec -it mysql mysql -uroot -pafe123456 -h127.0.0.1 -e "SHOW REPLICA STATUS\G"

确认:

  • Replica_IO_Running: 应为 Yes
  • Replica_SQL_Running: 应为 Yes
  • Last_IO_Error / Last_SQL_Error: 应为空
  • Seconds_Behind_Source: 延迟应逐渐减小

至此,全量备份还原与主从(含主库侧)复制配置完成。

2.3 注意事项

  1. 备份时机: 建议在业务低峰期执行备份,减少对业务的影响
  2. 网络传输: 确保备份机和还原机之间网络畅通,备份文件较大时传输可能需要较长时间
  3. 磁盘空间: 确保还原机有足够的磁盘空间存放备份文件和临时解压文件;还原前清空 /data/mysql/data 前请确认该路径为当前 MySQL 数据目录
  4. 权限要求: 脚本需要 MySQL root 权限,以及 /data/backup/mysql/、/data/mysql/data 等目录的相应权限
  5. GTID 一致性: 还原脚本会自动处理 GTID,确保复制能够正常继续
  6. 还原前准备: 还原前必须在还原机上删除 /data/mysql/data 数据并重启 MySQL 容器(步骤 3),再执行还原脚本,避免旧数据与备份冲突
  7. 账号与复制顺序: 还原后先创建账号(步骤 5),再在还原机配置指向主库的复制并检查状态(步骤 6),最后在主库上配置指向还原机的复制并检查状态(步骤 7),确保双向复制正常