【MySQL深入解析(9)】——主从复制架构详解
主从复制(Replication)是MySQL高可用架构的核心机制之一,它允许将主库(Master)的变更实时或异步同步到从库(Slave),实现读写分离、数据备份、故障转移等功能。在大规模分布式系统中,主从复制能显著提升系统的可用性和扩展性。
本文从原理、架构、类型对比、配置实战到常见问题,一步步深入剖析主从复制。假设你已掌握MySQL基础知识,我们会结合实际代码和配置示例讲解(基于MySQL 8.0+)。
一、主从复制的基本原理
主从复制的核心是基于二进制日志(Binary Log)的异步复制。原理简述:
- 主库(Master)记录变更:Master将所有写操作(INSERT/UPDATE/DELETE等)记录到binlog中(一种二进制格式的事件日志)。
- 从库(Slave)拉取日志:Slave的IO线程连接Master,请求并拉取binlog事件。
- 从库回放日志:Slave的SQL线程解析并执行这些事件,实现数据同步。
流程图示意图(文本版):
Master Slave
│ │
▼ ▼
写操作 → binlog → IO Thread → relay log → SQL Thread → 执行
│ │
└─ 异步/半同步反馈 ───────────────┘
关键机制:
- binlog格式:ROW(行级,推荐)、STATEMENT(语句级)、MIXED(混合)。
- 位点(Position)或GTID:用于追踪复制进度,避免重复或丢失。
二、主从复制的架构组件
主从复制涉及多个关键组件:
| 组件 | 作用 | 位置 | 配置参数示例 | 注意事项 |
|---|---|---|---|---|
| Binary Log (binlog) | Master记录所有变更事件 | Master | log_bin = /var/log/mysql/binlog | 必须开启(server-id 唯一) |
| Relay Log | Slave临时存储从Master拉取的日志 | Slave | relay_log = /var/log/mysql/relay | 用于回放,崩溃后可恢复 |
| IO Thread | Slave连接Master,拉取binlog | Slave | — | 监控:SHOW SLAVE STATUS |
| SQL Thread | Slave解析relay log并执行SQL | Slave | — | 单线程/多线程(parallel_replication) |
| Master Info | Slave记录Master的连接信息和位点 | Slave | master_info_repository = TABLE | 8.0+推荐用表存储,避免文件损坏 |
| Relay Info | Slave记录relay log的执行位点 | Slave | relay_log_info_repository = TABLE | 同上 |
典型架构:
- 一主一从:简单备份/读写分离。
- 一主多从:高读负载场景。
- 级联复制:Master → 中间Slave → 最终Slave(减少Master压力)。
- 双主互备:结合MHA/Orchestrator实现高可用。
三、复制类型对比(异步 vs 半同步 vs 全同步 vs GTID)
MySQL复制有多种模式,根据一致性需求选择:
| 类型 | 描述 | 一致性 | 性能影响 | 配置参数 | 适用场景 |
|---|---|---|---|---|---|
| 异步复制 (默认) | Master不等待Slave确认,直接返回成功 | 弱(可能丢失) | 最小 | replicate_do_db 等 | 高性能读写分离 |
| 半同步复制 | Master至少等待一个Slave确认后返回 | 中等(至少一Slave成功) | 中等 | rpl_semi_sync_master_enabled = 1 | 平衡一致性和性能 |
| 全同步复制 | Master等待所有Slave确认后返回 | 强 | 最大(瓶颈于最慢Slave) | group_replication (MySQL 5.7+) | 高一致性需求(如金融) |
| GTID复制 | 基于全局事务ID的复制(不依赖位点) | 与异步/半同步结合 | 略增 | gtid_mode = ON enforce_gtid_consistency = ON | 故障转移、自动恢复 |
GTID(Global Transaction Identifier)详解:
- 格式:
server_uuid:transaction_id(e.g.,123e4567-e89b-12d3-a456-426614174000:1-100) - 优势:Slave可自动跳过已执行事务,避免手动处理位点。
- 配置示例:在my.cnf中添加
gtid_mode=ON。
四、配置实战(一步步搭建主从复制)
假设两台服务器:Master(192.168.1.10)、Slave(192.168.1.11)。确保防火墙开放3306端口。
1. Master 配置(/etc/my.cnf)
[mysqld]
server-id = 1 # 唯一ID
log-bin = /var/log/mysql/binlog # 开启binlog
binlog-format = ROW # 推荐ROW格式
gtid_mode = ON # 开启GTID(可选)
enforce_gtid_consistency = ON
重启MySQL:systemctl restart mysqld
创建复制用户:
CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
查看Master状态:
SHOW MASTER STATUS; -- 记录File和Position(或GTID)
2. Slave 配置(/etc/my.cnf)
[mysqld]
server-id = 2 # 唯一ID
relay-log = /var/log/mysql/relay
read_only = ON # 只读模式(可选)
重启MySQL。
3. Slave 启动复制
CHANGE MASTER TO
MASTER_HOST = '192.168.1.10',
MASTER_USER = 'repl',
MASTER_PASSWORD = 'password',
MASTER_LOG_FILE = 'binlog.000001', -- 从 SHOW MASTER STATUS 获取
MASTER_LOG_POS = 123; -- 同上
-- 或 GTID 模式
CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
START SLAVE;
SHOW SLAVE STATUS\G; -- 检查 Slave_IO_Running 和 Slave_SQL_Running 是否 Yes
4. Python 代码验证(用pymysql操作主从)
import pymysql
# Master 连接
master_conn = pymysql.connect(host='192.168.1.10', user='root', password='pwd', db='test')
master_cur = master_conn.cursor()
master_cur.execute("INSERT INTO users (name) VALUES ('Alice')")
master_conn.commit()
# Slave 连接(读)
slave_conn = pymysql.connect(host='192.168.1.11', user='root', password='pwd', db='test')
slave_cur = slave_conn.cursor()
slave_cur.execute("SELECT name FROM users")
print(slave_cur.fetchone()) # ('Alice',) -- 稍等片刻即可看到
五、常见问题与监控
- 复制延迟:Slave_IO_Running=Yes,但Seconds_Behind_Master > 0。
- 原因:网络慢、大事务、Slave负载高。
- 解决:并行复制(slave_parallel_workers=8)、优化SQL、GTID自动恢复。
- Slave崩溃恢复:用
CHANGE MASTER TO重设位点或GTID。 - 监控工具:
SHOW SLAVE STATUS\G:手动检查。- Prometheus + mysqld_exporter:监控延迟、错误。
- Percona Toolkit(pt-heartbeat):精确测延迟。
- Orchestrator/MHA:自动故障转移。
- 常见错误:
- Duplicate entry:GTID模式下自动跳过。
- Slave SQL error:检查binlog格式一致性。
六、总结
主从复制是MySQL实现高可用的基石,默认异步模式性价比最高,结合GTID和半同步能进一步提升可靠性。实际生产中,建议从一主一从起步,逐步扩展到多从/级联,并集成监控和自动 failover 工具。
下一期我们会深入“读写分离与负载均衡”的实战配置。
有疑问吗?比如GTID的具体配置细节、Python异步操作MySQL的代码、或某个错误的具体排查?欢迎留言~