MySQL 主从复制配置:binlog、relay-log 与半同步复制

小飞兽 MySQL 4 次阅读 2026-07-29

前言

主从复制是 MySQL 实现数据高可用和读写分离的基础。在生产环境中,合理配置主从复制可以显著提升数据库的可用性和读取吞吐能力。本文将详细讲解 MySQL 主从复制的工作原理、binlog 的机制、三种复制模式以及半同步复制的配置与故障处理。

主从复制工作原理

MySQL 主从复制的核心是 binlog(二进制日志)。主库将所有数据变更记录到 binlog,从库通过 I/O 线程读取主库的 binlog 并写入本地的 relay-log(中继日志),再由 SQL 线程重放 relay-log 中的事件,最终实现数据同步。

整个复制链路涉及三个线程:

  • <strong>Master Binlog Dump 线程</strong>:主库推送 binlog 事件给从库

  • <strong>Slave I/O 线程</strong>:从库读取主库的 binlog,写入本地 relay-log

  • <strong>Slave SQL 线程</strong>:从库重放 relay-log 中的事件

-- 主库:查看 binlog 状态
SHOW MASTER STATUS;
-- 返回当前 binlog 文件名和位置,这是从库复制的起点

-- 从库:查看复制链路状态
SHOW SLAVE STATUS\G
-- 关键字段:
-- Slave_IO_Running: I/O 线程状态
-- Slave_SQL_Running: SQL 线程状态
-- Seconds_Behind_Master: 复制延迟(秒)
-- Exec_Master_Log_Pos: 已执行的主库 binlog 位置

binlog 格式详解

binlog 有三种格式,格式选择直接影响复制能力和数据一致性:

ROW 格式:记录每行数据的实际变更。优点是精确,不会有主从数据不一致的问题;缺点是日志量最大。

STATEMENT 格式:记录每条 SQL 语句。优点是日志量小;缺点是某些不确定函数(如 NOW()、RAND())在主从执行结果可能不同。

MIXED 格式:MySQL 自动在 STATEMENT 和 ROW 之间选择,一般使用 STATEMENT,遇到不确定语句时切换为 ROW。

-- 主库配置 binlog 格式(在 my.cnf 中配置)
[mysqld]
server-id = 1
log-bin = /var/lib/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 100M

-- 查看当前 binlog 格式
SHOW VARIABLES LIKE 'binlog_format';

-- 清理 binlog
PURGE BINARY LOGS BEFORE '2024-01-01 00:00:00';
RESET MASTER;  -- 危险:删除所有 binlog,重新开始

主从复制配置实战

-- 步骤1:主库配置
[mysqld]
server-id = 1
log-bin = /var/lib/mysql/mysql-bin
binlog_format = ROW
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1

-- 创建复制专用账户
CREATE USER 'repl'@'%' IDENTIFIED BY 'ReplPassword123!';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

-- 锁定主库并获取复制起点
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;  -- 记录 File 和 Position
-- 在另一终端用 mysqldump 导出数据
-- 完成后 UNLOCK TABLES;

-- 完整数据导出
-- mysqldump -h 127.0.0.1 -u root -p --all-databases --master-data=2 --single-transaction > backup.sql

-- 步骤2:从库配置
[mysqld]
server-id = 2
relay-log = /var/lib/mysql/mysql-relay-bin
relay_log_purge = ON
read_only = ON
super_read_only = ON

-- 配置主从复制链路
CHANGE MASTER TO
    MASTER_HOST = '192.168.1.100',
    MASTER_PORT = 3306,
    MASTER_USER = 'repl',
    MASTER_PASSWORD = 'ReplPassword123!',
    MASTER_LOG_FILE = 'mysql-bin.000001',
    MASTER_LOG_POS = 123456,
    GET_MASTER_PUBLIC_KEY = 1;

-- 启动复制
START SLAVE;

-- 验证复制状态
SHOW SLAVE STATUS\G

GTID 复制模式

GTID(Global Transaction Identifier)是 MySQL 5.6+ 引入的复制方式,每个事务都有一个全局唯一标识符,格式为 server_uuid:transaction_id。GTID 大幅简化了主从故障切换和位置管理。

-- 主库启用 GTID
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON

-- 从库启用 GTID
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
server-id = 2

-- GTID 模式下,无需指定 MASTER_LOG_FILE 和 MASTER_LOG_POS
CHANGE MASTER TO
    MASTER_HOST = '192.168.1.100',
    MASTER_PORT = 3306,
    MASTER_USER = 'repl',
    MASTER_PASSWORD = 'ReplPassword123!',
    MASTER_AUTO_POSITION = 1;

-- 查看 GTID 状态
SHOW MASTER STATUS;
SHOW SLAVE STATUS\G

-- 从库跳过错误事务(慎用)
SET @@SESSION.GTID_NEXT = 'server_uuid:transaction_id';
BEGIN; COMMIT;
SET @@SESSION.GTID_NEXT = AUTOMATIC;

半同步复制

异步复制(默认)下,主库提交事务后立即返回客户端成功,不等待从库确认。如果主库崩溃,已复制到从库的数据可能丢失。

半同步复制(Semi-Synchronous Replication) 要求主库在提交事务前,至少等待一个从库确认接收了 binlog 数据。

-- 主库安装半同步插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

-- 从库安装半同步插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

-- 启用半同步(在主库执行)
SET GLOBAL rpl_semi_sync_master_enabled = ON;
SET GLOBAL rpl_semi_sync_master_timeout = 10000;  -- 毫秒

-- 启用半同步(在从库执行)
SET GLOBAL rpl_semi_sync_slave_enabled = ON;

-- 重启从库的复制
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

-- 验证半同步状态
SHOW STATUS LIKE 'Rpl_semi_sync_master%';

主从延迟与故障处理

-- 监控主从延迟
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master: 0 表示无延迟

-- 延迟原因排查
-- 1. 从库负载过高(SQL 线程单线程重放)
-- 2. 大事务导致从库重放慢
-- 3. 网络延迟

-- 解决方案:并行复制(MySQL 5.7+)
STOP SLAVE;
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL slave_parallel_workers = 8;
START SLAVE;

-- 主从切换(故障转移)
-- 1. 确认从库已完全同步
-- 2. 将从库设为只读
SET GLOBAL read_only = ON;
SET GLOBAL super_read_only = ON;
-- 3. 停止从库复制
STOP SLAVE;
-- 4. 重置从库配置
RESET SLAVE ALL;

常见问题

Q1:主从数据不一致如何处理?
可以使用 pt-table-checksum 工具检测不一致,然后使用 pt-table-sync 工具修复。对于小表,可以直接重新导入主库数据后重新建立复制链路。

Q2:从库延迟很大怎么处理?
常见原因是大事务在主库快速执行完毕,但从库单线程重放导致延迟。解决方案包括:将大事务拆小、使用并行复制、或使用 ShardingSphere 等中间件进行分片。

Q3:如何防止误操作同步到从库?
使用 sql_log_bin = 0 可以让当前会话的操作不记入 binlog。但注意这不会记录到 binlog,无法通过 binlog 恢复。

延伸阅读

  • MySQL 分库分表与读写分离策略
  • MySQL 慢查询分析与优化
  • MySQL 官方文档:Replication https://dev.mysql.com/doc/refman/8.0/en/replication.html