MySQL主从复制原理与配置 MySQL 是业务系统中最常见的数据库,但用好它并不容易。索引设计、SQL 优化、事务处理都是日常开发中需要关注的点。本文从实际场景出发,讲常见问题和解决思路。
一、复制架构概述 #
1.1 复制的作用
读写分离 :主库写,从库读,分摊压力
数据备份 :从库作为实时备份
高可用 :主库故障时切换到从库
统计分析 :报表查询在从库执行
#
1.2 复制模式演进 MySQL 3.23: 异步复制(Asynchronous Replication) MySQL 5.5: 半同步复制(Semi-Synchronous Replication) MySQL 5.6: GTID复制(Global Transaction Identifier) MySQL 5.7: 组复制(Group Replication) MySQL 8.0: 增强GTID、克隆插件
二、复制原理 #
2.1 核心流程 Master Slave │ │ │ 1. 写操作 │ │ ──────────────────────> │ │ │ │ 2. 写binlog │ │ ┌─────────────┐ │ │ │ binlog │ │ │ └─────────────┘ │ │ │ │ 3. Dump线程发送binlog │ │ ──────────────────────> │ │ │ 4. I/O线程接收写入relay log │ │ │ │ 5. SQL线程重放relay log │ │
#
2.2 复制线程 主库线程 :
Binlog Dump Thread :发送binlog给从库
从库线程 :
I/O Thread :连接主库,接收binlog,写入relay log
SQL Thread :读取relay log,重放SQL
#
2.3 binlog格式
格式
特点
优点
缺点
STATEMENT
记录SQL语句
日志小
某些语句不一致(UUID、NOW()等)
ROW
记录行变更
精确、安全
日志大
MIXED
混合模式
平衡
复杂
推荐 :MySQL 5.7+ 使用ROW格式
[mysqld] binlog_format = ROW
#
2.4 复制方式 异步复制(Asynchronous) :
主库写完binlog即返回,不等待从库
性能最好,但存在数据延迟和丢失风险
半同步复制(Semi-Synchronous) :
主库等待至少一个从库确认收到binlog
平衡性能和数据安全
组复制(Group Replication) :
基于Paxos协议
多数节点确认才提交
自动故障切换
三、异步复制配置 #
3.1 主库配置 [mysqld] server-id = 1 log-bin = mysql-binbinlog_format = ROWexpire_logs_days = 7 sync_binlog = 1 innodb_flush_log_at_trx_commit = 1
创建复制账号:
CREATE USER 'repl' @'%' IDENTIFIED BY 'password' ;GRANT REPLICATION SLAVE ON * .* TO 'repl' @'%' ;FLUSH PRIVILEGES;
查看主库状态:
+------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000001 | 154 | | | +------------------+----------+--------------+------------------+
#
3.2 从库配置 [mysqld] server-id = 2 relay-log = mysql-relay-binread_only = ON log-bin = OFF
配置主库连接:
CHANGE MASTER TO MASTER_HOST = 'master_host' , MASTER_PORT = 3306 , MASTER_USER = 'repl' , MASTER_PASSWORD = 'password' , MASTER_LOG_FILE = 'mysql-bin.000001' , MASTER_LOG_POS = 154 ; START SLAVE;
#
3.3 验证复制状态
关键字段: | 字段 | 正常状态 | |——|———| | Slave_IO_Running | Yes | | Slave_SQL_Running | Yes | | Seconds_Behind_Master | 0或较小数字 | | Last_IO_Error | 空 | | Last_SQL_Error | 空 |
四、GTID复制 #
4.1 什么是GTID GTID(Global Transaction Identifier)是全局事务标识符:
GTID = source_id:transaction_id 示例: 3E11FA47-71CA-11E1-9E33-C80AA9429562:23
#
4.2 GTID优势
定位方便 :直接知道事务在哪个库执行
切换简单 :不需要指定binlog文件名和位置
一致性强 :避免重复执行或遗漏事务
#
4.3 GTID配置 主库和从库都需配置:
[mysqld] server-id = 1 log-bin = mysql-binbinlog_format = ROWgtid_mode = ON enforce_gtid_consistency = ON
从库配置:
CHANGE MASTER TO MASTER_HOST = 'master_host' , MASTER_PORT = 3306 , MASTER_USER = 'repl' , MASTER_PASSWORD = 'password' , MASTER_AUTO_POSITION = 1 ; START SLAVE;
#
4.4 GTID相关操作 SHOW GLOBAL VARIABLES LIKE '%gtid%' ;SHOW MASTER STATUS; SHOW SLAVE STATUS \G; SET GTID_NEXT= '3E11FA47-71CA-11E1-9E33-C80AA9429562:23' ;BEGIN ; COMMIT ;SET GTID_NEXT= 'AUTOMATIC' ;
五、半同步复制 #
5.1 安装插件 INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so' ; INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so' ;
#
5.2 启用半同步 SET GLOBAL rpl_semi_sync_master_enabled = 1 ;SET GLOBAL rpl_semi_sync_master_timeout = 1000 ; SET GLOBAL rpl_semi_sync_slave_enabled = 1 ;STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
#
5.3 验证半同步 SHOW STATUS LIKE 'Rpl_semi_sync_master_status' ;SHOW STATUS LIKE 'Rpl_semi_sync_master_clients' ;SHOW STATUS LIKE 'Rpl_semi_sync_slave_status' ;
六、常见复制问题 #
6.1 主从延迟 原因 :
从库性能差
大事务
锁等待
单线程SQL线程(5.6之前)
查看延迟 :
解决方案 :
并行复制(MySQL 5.6+)
slave_parallel_type = LOGICAL_CLOCKslave_parallel_workers = 4
分离大事务
升级从库硬件
使用缓存减少从库读压力
#
6.2 主从数据不一致 检测 :
pt-table-checksum --host=master --user=root --password=xxx \ --databases=mydb --replicate=mydb.checksums
修复 :
pt-table-sync --execute --replicate mydb.checksums \ h=master,u=root,p=xxx h=slave,u=root,p=xxx
#
6.3 复制中断 I/O线程中断 :
常见原因和解决:
网络中断 → 检查网络,重启slave
主库binlog被清理 → 重新同步数据
权限问题 → 检查复制账号权限
SQL线程中断 :
常见原因和解决:
主从数据不一致 → 跳过错误事务或重新同步
表不存在 → 检查是否遗漏DDL
STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1 ;START SLAVE;STOP SLAVE; SET GTID_NEXT= 'xxx:xxx' ;BEGIN ; COMMIT ;SET GTID_NEXT= 'AUTOMATIC' ;START SLAVE;
#
6.4 复制过滤 binlog-do-db = db1binlog-ignore-db = testreplicate-do-db = db1replicate-ignore-db = testreplicate-do-table = db1.table1replicate-wild-do-table = db1.%
七、读写分离实现 #
7.1 应用层实现 @Configuration public class DataSourceConfig { @Bean public DataSource routingDataSource () { DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource (); Map<Object, Object> targetDataSources = new HashMap <>(); targetDataSources.put("master" , masterDataSource()); targetDataSources.put("slave" , slaveDataSource()); routingDataSource.setTargetDataSources(targetDataSources); routingDataSource.setDefaultTargetDataSource(masterDataSource()); return routingDataSource; } } @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value () default "master" ; } @DataSource("slave") public List<User> getUsers () { return userMapper.selectAll(); }
#
7.2 中间件方案
中间件
特点
MyCat
功能全面,配置复杂
ShardingSphere
Apache项目,生态好
ProxySQL
轻量级,性能好
MaxScale
MariaDB官方
#
7.3 延迟处理 @Service public class OrderService { public void createOrder (Order order) { orderMapper.insert(order); Order freshOrder = orderMapper.selectByIdFromMaster(order.getId()); cache.put(order.getId(), freshOrder); } }
八、复制监控 #
8.1 关键监控指标 SHOW SLAVE STATUS \G;SELECT THREAD_ID, NAME, PROCESSLIST_COMMAND, PROCESSLIST_STATE FROM performance_schema.threads WHERE NAME LIKE '%slave%' ;SHOW MASTER LOGS;
#
8.2 自动化监控脚本 #!/bin/bash DELAY=$(mysql -e "SHOW SLAVE STATUS\G" | grep "Seconds_Behind_Master" | awk '{print $2}' ) if [ "$DELAY " = "NULL" ] || [ "$DELAY " -gt 60 ]; then echo "复制异常,延迟: ${DELAY} 秒" | mail -s "MySQL复制告警" dba@company.com fi
九、总结
复制模式
数据安全
性能
适用场景
异步复制
低
高
读扩展、备份
半同步复制
中
中
一般生产环境
组复制
高
低
金融级高可用
配置项
建议
binlog_format
ROW
sync_binlog
1(半同步)/ 1000(异步)
gtid_mode
ON
read_only
从库开启
slave_parallel_workers
CPU核数的一半
主从复制的核心要点:
选择合适的复制模式(异步/半同步/GTID)
监控复制延迟,及时发现和处理问题
合理设计读写分离策略
定期校验主从数据一致性
核心要点
索引设计的原则:最左前缀原则、避免索引列参与计算、选择合适的索引类型
SQL 优化的方法:使用 EXPLAIN 分析执行计划、避免 SELECT *、优化 JOIN
事务隔离级别的选择:根据业务需求选择合适的级别
常见的锁问题:行锁、表锁、死锁的处理
总结 MySQL 优化是一个持续的过程,需要结合业务特点和数据量来调整。在实际项目中,定期分析慢查询日志、优化索引、调整配置参数,都能提升数据库性能。