Mysql主从复制

MySQL 主从复制:原理与实战

一、理论

什么是主从复制

主从复制是一种数据库复制技术:把主库(Master / Source)的数据变更,实时或准实时地复制到一个或多个从库(Slave / Replica)。

本质是「主库记录变更 → 从库拉取 → 从库重放 」,因此它是异步复制:默认不保证零丢失,只保证最终一致。

原理与流程

text 复制代码
主库:数据变更 → 写入 binlog(二进制日志)
                        ↓
从库 I/O 线程:拉取主库 binlog → 写入本地 relay log(中继日志)    # 所以才会占 CPU 和 IO
                        ↓
从库 SQL 线程:读取 relay log → 重放变更 → 与主库保持一致

复制模式

模式 说明 特点
SBR(基于语句) 记录执行的 SQL 语句 日志小,但某些函数(如 NOW()、UUID())可能导致不一致
RBR(基于行) 记录每一行的变更 最安全、最常用,日志量较大
Mixed(混合) 由 MySQL 自动在两者间选择 兼容性折中

生产环境推荐 binlog_format = ROW。

主从复制的用途与意义

场景 说明
读写分离 主库负责写,从库负责读,提升整体吞吐
数据热备 主库故障时可快速切换到从库
负载均衡 多从库分散高并发查询压力
数据分析 在从库执行统计查询,避免影响主库

注意:因为是异步复制,从库从主库拉取会有延迟;要想立马写入立马读,可以在主库上进行。


二、实战

环境准备

  • 主从 MySQL 版本一致(大版本必须相同,建议小版本也一致)
  • server-id 全局唯一
  • 主从网络互通,开放 3306 端口(防火墙)
  • 两台机器时间同步(chrony / NTP),字符集与排序规则一致

主库配置

1. 配置文件
bash 复制代码
vim /etc/my.cnf
ini 复制代码
[mysqld]
server-id = 1                  # 主库唯一标识
log-bin = mysql-bin            # 启用二进制日志
binlog_format = ROW            # 推荐使用行格式
binlog_expire_logs_seconds = 604800   # binlog 保留 7 天
max_binlog_size = 512M

修改完以后记得重启 MySQL 服务:

bash 复制代码
systemctl restart mysqld

提示 :自定义日志路径(如 /var/log/mysql/mysql-bin.log)时,目录必须存在且属主为 mysql,否则服务启动失败;CentOS 上还会有 SELinux 标签问题。练习环境直接用默认路径最省事。

2. 配置从库登录账号

配置文件写完以后,还得配置从库登录账号,不要让从库直接有 root 权限:

sql 复制代码
CREATE USER 'repl'@'从库IP' IDENTIFIED BY 'Repl@2026';

-- 复制从库权限,允许该用户连接主库并读取二进制日志(binlog)
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'172.22.4.4';

FLUSH PRIVILEGES;

-- 查看账号
SELECT user, host, plugin FROM mysql.user WHERE user = 'repl';
3. 查看主库状态

从库部署好后,我们可以输入命令查看主库状态:

sql 复制代码
-- MySQL 8.4 之前
SHOW MASTER STATUS;

-- MySQL 8.4 及之后
SHOW BINARY LOG STATUS;

输出样例如下:

text 复制代码
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      747 |              |                  |
+------------------+----------+--------------+------------------+

记录 File 和 Position,从库配置会用到。

4. 主库已有数据怎么同步

但是还有个问题:主从复制完成之前,主库的数据该怎么同步?

在从库配置前,如果主库有数据,可以先进行一个全量备份导入到从库,保证初期数据一致性:

bash 复制代码
mysqldump -uroot -p --single-transaction --master-data=2 \
  --routines --triggers --events --all-databases \
  > /backup/full_$(date +%F).sql

再把这个文件导入从库。

从库配置

ini 复制代码
[mysqld]
server-id = 2                  # 必须与主库不同
relay-log = relay-bin          # 中继日志
read_only = 1                  # 普通用户只读,防止误写
super_read_only = 1            # 超级用户也只读
replica_parallel_workers = 4   # 多线程复制,缓解延迟
replica_parallel_type = LOGICAL_CLOCK
replica_preserve_commit_order = 1

提示 :read_only 和 super_read_only 在主从切换时需要去掉。

配置主从连接

主从库配置都好了以后,就可以配置连接:

IP + 端口定位主库,数据库账户密码获取权限,再加上之前主库查的 File + Position。

sql 复制代码
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST        = '主库IP',
  SOURCE_USER        = 'repl',
  SOURCE_PASSWORD    = 'Repl@2026',
  SOURCE_PORT        = 3306,
  SOURCE_LOG_FILE    = 'mysql-bin.000001',
  SOURCE_LOG_POS     = 747,
  GET_SOURCE_PUBLIC_KEY = 1,      -- 8.0 默认 caching_sha2_password 时需要
  SOURCE_SSL         = 0;

START REPLICA;

注意:这段是要在数据库里执行。

另一种模式:GTID 模式

GTID 模式(推荐,免去手工算位置)

主从都配置:

ini 复制代码
gtid_mode = ON
enforce_gtid_consistency = ON

从库只需:

sql 复制代码
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='172.22.4.3',
  SOURCE_USER='repl',
  SOURCE_PASSWORD='Repl@2025',
  SOURCE_AUTO_POSITION = 1;

START REPLICA;

验证主从复制的效果

到这里主从复制就完成了,我们来验证一下主从复制的效果。

查看同步状态:

sql 复制代码
SHOW REPLICA STATUS\G;   -- MySQL 8.0.22 及之后
SHOW SLAVE STATUS\G;     -- MySQL 8.0.22 之前

查询到的结果对照下面的指标表即可。

重点指标:

指标 期望值 说明
Replica_IO_Running Yes I/O 线程正常拉取主库 binlog
Replica_SQL_Running Yes SQL 线程正常重放
Seconds_Behind_Source 接近 0 复制延迟秒数
Last_IO_Error 空 I/O 线程错误
Last_SQL_Error 空 SQL 线程错误

旧版本命令显示的字段名是 Slave_IO_Running / Slave_SQL_Running。

之后可以在主库创建数据库表,从库查看来验证,这里就不展开了。


三、主从常用命令

sql 复制代码
-- 查看状态
SHOW REPLICA STATUS\G;

-- 停止/启动复制
STOP REPLICA;
START REPLICA;

-- 重置主从关系(清空复制信息)
STOP REPLICA;
RESET REPLICA ALL;

-- 旧语法(8.0 之前)
STOP SLAVE;
RESET SLAVE ALL;

主从切换(从库提升为主库)的大致操作:

sql 复制代码
STOP REPLICA;
RESET REPLICA ALL;
SET GLOBAL read_only = OFF;
SET GLOBAL super_read_only = OFF;

注意:这些命令都在从库数据库执行。


四、常见故障与处理

问题 原因 解决
连接失败(2003) 网络不通、防火墙未放行、账号权限不足 检查 3306、云安全组、账号是否限定 IP
认证失败 密码错误或认证插件不兼容 GET_SOURCE_PUBLIC_KEY=1,或改用 mysql_native_password
Last_IO_Error: 1236 指定的 binlog 文件不存在(已被清理) 重新全量导出并重新配置位置
主键冲突(1062) 从库被写入过数据或数据不一致 检查 read_only,校验数据后重建从库
同步延迟过高 大事务、慢查询、单线程重放、从库资源不足 开启多线程复制、拆分大事务、优化慢查询、提升硬件
主从数据不一致 误操作、跳过错误、非确定性语句 用 pt-table-checksum 校验并修复
SQL 线程停止 表不存在、字段不匹配等 先看 Last_SQL_Error,修复后重启复制
相关推荐
暖核1 小时前
MySQL 高级运维核心:备份恢复、主从复制与 MHA 高可用复习总结
运维·数据库·mysql
jackletter1 小时前
linux:systemd之守护进程
linux·运维·服务器·systemd
Ruiery2 小时前
Linux 6.6内核 CPU 深度解析(五):CPU 空闲状态机 cpuidle
linux·运维·服务器
XS0301062 小时前
Nginx 学习指南
运维·nginx
Lsetea3 小时前
OpenSSL verify报invalid CA certificate:basicConstraints与keyCertSign排查
运维·https·ssl证书·openssl·证书链
程序猿老A3 小时前
云服务器怎么配置OSS?
运维·服务器
对讲机数码科普3 小时前
数字集群对讲工程全流程拆解:DMR/ePDT 制式选型、组网落地与运维实战
运维·软件工程
加油yx3 小时前
数据库基础
数据库
天桥下的卖艺者3 小时前
chrals.CTI函数升级版发布,增加了CTI衍生的脂肪指数提取
数据库·r语言