主从原理
核心作用
数据热备份、故障切换;
读写分离:主库写、从库读、分担查询压力;
数据分发、异地多活、数据审计;
整体架构与三大线程
主从复制依赖二进制日志 binlog传输数据,一共 3 个核心线程:
主库:Dump 线程(Binlog Dump Thread)
当从库 IO 线程连接主库后,主库创建 Dump 线程;
读取本地 binlog 文件,将新增日志实时推送给从库 IO 线程;
多个从库连接主库,主库会生成多条独立 Dump 线程。
从库:IO 线程(Slave_IO_Running)
连上主库,请求 binlog 数据;
接收主库发来的日志,写入本地的中继日志(Relay Log);
记录当前已接收到哪个位置,断线后能接着续传。
从库:SQL 线程(Slave_SQL_Running)
读取中继日志里的 binlog 事件;
在从库上重放执行这些事件(重新执行 SQL 或行变更);
记录已执行到的位置,执行完的中继日志可以清理。
补充总结:
两个关键文件(在实际运维中常被问及):
master.info:记录 IO 线程拉取到的 binlog 位置(主库的哪条日志);
relay-log.info:记录 SQL 线程回放到的位置(中继日志的哪条)。复制方式的定性:
默认是异步复制——主库写完 binlog 就返回成功,不管从库有没有收到;
如需强一致性,可改用半同步复制(至少一个从库收到日志后才返回)。
常见架构
一主一从:最简单架构,主库写,从库读+备份;
一主多从:主库写,多从库分担读压力(适合读密集场景);
级联复制(主→从→从):主库只同步给一个从库(二级主库),再由二级主库同步给其他从库,减轻主库的 dump 线程压力;
双主复制:两个主库互为主从,均可写操作(需避免冲突,适合写分散场景)。
复制类型
1. 异步复制(默认)
流程:主库执行完写操作 → 写入 binlog → 立即向客户端返回成功(不等待从库同步);
优点:性能好(主库无等待);
缺点:主库崩溃时,可能有数据未同步到从库,导致数据丢失。
2. 半同步复制(Semi-Sync)
流程:主库执行完写操作 → 写入 binlog → 等待至少一个从库收到 binlog 并写入中继日志 → 向客户端返回成功;
优点:数据安全性高于异步(至少一个从库有备份);
缺点:性能略低于异步(主库需等待从库确认)。
3. 全同步复制(Full-Sync)
流程:主库执行完写操作 → 等待所有从库执行完 binlog 事件并返回成功 → 向客户端返回成功;
优点:数据零丢失(主从数据完全一致);
缺点:性能差(主库等待时间长,适合对数据一致性要求极高的场景)。
主从配置设置
主库配置
# 配置 my.cnf vim /etc/my.cnf # 配置文件内容(在mysqld下面添加) [mysqld] # 主从复制-主机配置 # 主服务器唯一ID server-id=1 # 启用二进制日志 log-bin=mysql-bin # 在数据目录创建日志等价于 log-bin=/usr/local/mysql/data/mysql-bin # 设置不要复制的数据库(可设置多个) binlog-ignore-db=sys binlog-ignore-db=mysql binlog-ignore-db=information_schema binlog-ignore-db=performance_schema # 设置需要复制的数据库(可设置多个) # binlog-do-db=test # 设置logbin格式 binlog_format=STATEMENT
从库配置
# 配置 my.cnf vim /etc/my.cnf # 配置文件内容(在mysqld下面添加) [mysqld] # 在之前配置下方编写 # 主从复制-从机配置 # 从服务器唯一ID server-id=2 # 启用中继日志 relay-log=mysql-relay # 在数据目录创建日志等价于 relay-log= /usr/local/mysql/data/mysql-relay
重启服务
# 重启两台服务器上的mysql systemctl restart mysqld
关闭防火墙或开放3306端口
# 关闭主从数据库服务器防火墙或开放3306端口 ## 查看防火墙状态 systemctl status firewalld ## 关闭防火墙 systemctl stop firewalld # 永久开放3306端口 firewall-cmd --permanent --add-port=3306/tcp # 重新加载防火墙规则 firewall-cmd --reload # 验证是否生效 firewall-cmd --list-ports
主数据库创建用户slave并授权
# 主数据库创建用户slave并授权 ## 在主数据库端(192.168.7.21) ## 登录mysql -uroot -p ## 创建用户 create user 'slave'@'%' identified with mysql_native_password by '123456'; ## 授权 grant replication slave on *.* to 'slave'@'%'; ## 刷新权限 flush privileges;
从数据库端验证主数据库slave用户是否可用
# 从数据库端验证主数据库slave用户是否可用 ## 在从数据库端(192.168.7.22) ## 验证主数据库slave用户是否可用 mysql -uslave -p -h192.168.7.21 -P3306 # 成功提示 会进入主数据库
配置主从节点信息
# 配置主从节点信息 ## 在主数据库端(192.168.7.21) ## 查询服务ID及Master状态 ## 登录 mysql -uroot -p # 查询server_id是否可配置文件中一致 show variables like 'server_id'; # 若不一致,可设置临时ID(重启失效) set global server_id = 100; # 查询Master状态,并记录 File(对应下一步中的master_log_file) # Position (对应下一步中的master_log_pos)的值 show master status; # 注意:执行完此步骤后退出主数据库 # 防止再次操作导致 File 和 Position 的值发生变化
在从数据库端设置同步
# 在从数据库端设置同步 # 在从数据库端(192.168.7.22) # 登录 mysql -uroot -p # 查询server_id是否可配置文件中一致 show variables like 'server_id'; # 若不一致,可设置临时ID(重启失效) set global server_id = 101; # 设置主数据库参数(用上一步创建的slave用户及密码) change master to master_host='192.168.7.21', master_port=3306, master_user='slave', master_password='123456', master_log_file='mysql-bin.000001', -- 主服务器提供 master_log_pos=828; -- 主服务器提供 # 开始同步 start slave; # 查询Slave状态 show slave status\G; # 查看是否配置成功 # 查看参数 Slave_IO_Running 和 Slave_SQL_Running 是否都为yes,则证明配置成功。若为no,则需要查看对应的 Last_IO_Error 或 Last_SQL_Error 的异常值 # 若出现错误,则停止同步,重置后再次启动 stop slave; reset slave; start slave; # 可以在从服务器my.cnf中添加 slave_skip_errors = ALL # 跳过错误,继续同步 # 重启MySQL服务 systemctl restart mysqld
测试是否成功
测试主从复制,主服务上执行
# 在主数据库端(192.168.7.21) mysql -uroot -p # 创建test库,t1表,添加测试数据 create database test; use test; create table t1(id int,name varchar(30)); insert into t1(id,name) values(1,"aaa");测试主从复制,从服务器上执行
# 在从数据库端(192.168.7.22) mysql -uroot -p # 查看是否同步数据 show databases; use test; show tables; select * from t1;
GTID 方案
GTID 的全称是 Global Transaction Identifier,全局事务 ID,当一个事务提交时,就会生成一个 GTID,相当于事务的唯一标识。
GTID 长这样:
c5d74746-d7ec-11ec-bf8f-0242ac110002:1结构:
GTID=server_uuid:gno
如何配置
# 修改主库和从库的配置文件:
vim /etc/my.cnf
# 添加配置文件
[mysqld]
## 在配置文件中添加GTID配置
gtid_mode=on
enforce_gtid_consistency=on
解释:
gtid_mode=on #GTID 是一个全局唯一的事务标识符,用于标识数据库集群中的事务。启用 GTID 后,每个事务都会被分配一个唯一的 GTID。
enforce_gtid_consistency=on #当启用 GTID 后,该选项用于强制要求从库只能复制具有与主库一致的 GTID 链的事务,以确保数据一致性。
# 从库配置同步的参数:
## 格式
CHANGE MASTER TO
MASTER_HOST=$host_name,
MASTER_PORT=$port,
MASTER_USER=$user_name,
MASTER_PASSWORD=$password,
master_auto_position=1;
## 例如:
change master to
master_host='192.168.8.100',
master_port=3306,
master_user='slave',
master_password='root123',
master_auto_position=1;GTID和传统模式切换方法
在线将传统复制切换到GTID复制
## 在主从库执行
set global enforce_gtid_consistency=WARN;
set global enforce_gtid_consistency=on;
set @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
## 先在从库上执行
set @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
## 然后在主库执行
set @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
# 查看是否为0,等于0是表示所有连接都转为gtid复制
show status like 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';
# 主从库执行
set global gtid_mode=on;
# 从库执行
stop slave;
change master to master_auto_position=1;
start slave;
## 永久生效,记得更改配置文件在线将GTID的环境切换到非GTID
# 从库执行
stop slave;
change master to master_auto_position=0;
start slave;
# 主从库执行
set @@GLOBAL.GTID_MODE = ON_PERMISSIVE
# 主库执行
set @@GLOBAL.GTID_MODE = OFF_PERMISSIVE
# 这个时候已经从gtid转到传统复制了,不过还是中间状态
# 在从库执行
set @@GLOBAL.GTID_MODE = OFF_PERMISSIVE
# 主从库执行
select @@GLOBAL.GTID_OWNED;
# 是不是为空
# 主库执行
set global gtid_mode=0;
# 主库执行
set global enforce_gtid_consistency=off;
## 永久生效,记得配置文件修改MySQL主从
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法