【MySQL】MySQL主从复制原理解析:从二进制日志到数据一致性
本专栏文章持续更新,新增内容使用蓝色表示。
一、MySQL复制基础
MySQL的主从复制采用异步单向架构,支持两种核心复制方式:
基于语句的复制(Statement-Based Replication, SBR)
基于行的复制(Row-Based Replication, RBR)
两种方式均基于主库的二进制日志(Binary Log)和从库的中继日志(Relay Log)实现数据同步。
主要应用场景
读写分离:主库处理写操作,从库承担读请求
负载均衡:分散数据库访问压力
数据安全:提供数据备份能力(需注意:复制≠备份)
高可用性:避免单点故障,实现故障转移
滚动升级:在不中断服务的情况下进行版本升级
二、二进制日志
二进制日志记录所有对数据库的更改事件(注意:SELECT等读操作不会被记录)。通过设置log-bin系统变量开启(默认已开启)。
2.1 核心作用
数据复制的基础
数据恢复:还原备份后,重新执行后续的二进制日志事件
2.1 二进制日志格式对比
格式类型 | 工作原理 | 优点 | 缺点 |
---|---|---|---|
STATEMENT | 记录修改数据的SQL语句 | 日志量小,性能优秀 | 非确定性函数(如NOW()、RAND())可能导致主从不一致 |
ROW | 记录每行数据的修改细节 | 数据准确性高,复制可靠 | 日志量庞大,可能影响性能 |
MIXED | 混合模式,智能切换 | 兼顾性能与准确性 | 切换逻辑复杂,需MySQL自动判断 |
MIXED格式:默认采用STATEMENT格式,在检测到可能引发不一致的操作时自动切换为ROW格式。
三、MySQL复制流程
3.1 五步复制流程
1)主库日志记录
主库开启二进制日志,记录所有数据更改事件
2)从库请求事件
从库I/O线程向主库发起二进制日志事件查询
3)事件传输
主库Binlog Dump线程向从库I/O线程发送二进制日志事件
4)中继日志写入
从库I/O线程将接收的事件写入本地中继日志
5)事件重放
从库SQL线程读取中继日志并重放事件到从库
3.2 复制流程特点
1)异步设计优势:
事件获取与重放解耦,支持异步执行
主从网络中断不影响主库性能
2)性能瓶颈:
默认配置下,主库并发更新在从库上串行执行(单SQL线程)
解决方案:配置slave_parallel_workers启用并行复制
3)级联复制:
通过log_slave_updates系统变量控制从库是否记录二进制日志
支持多级复制架构
3.3 异步复制的优缺点
优点:
性能优秀,对主库影响小
缺点:
数据一致性:无法保证主从实时一致
数据丢失风险:主库宕机时,已提交事务可能未传输到从库
切换风险:强制主从切换可能导致数据丢失
3.4 解决方案:半同步复制
针对异步复制的缺陷,MySQL提供了半同步复制(Semisynchronous Replication):
确保事务至少传输到一个从库后才向客户端返回成功
显著降低数据丢失风险
在数据一致性与性能之间取得平衡
四、InnoDB的重做日志
4.1 重做日志的作用
InnoDB存储引擎维护重做日志(Redo Log),具有以下特点:
记录所有对InnoDB表的修改操作
解决"脏页"未刷盘时的数据丢失问题
支持数据库实例异常关闭后的数据恢复
4.2 MySQL三层架构与日志关系
连接层:客户端连接管理、认证授权。
服务器层:SQL解析、优化、缓存、内置功能。二进制日志在此层实现。
存储引擎层:数据存储与提取。重做日志在此层实现(InnoDB)。
五、数据一致性保障机制
5.1 日志协同工作要求
在主从复制环境中,确保数据一致性需要满足:
存在性保证:二进制日志中的事件必须在重做日志中存在
顺序一致性:两种日志中的事务顺序必须一致
因此,MySQL以二进制日志的写入作为事务提交成功的最终标志。
5.2 关键技术:两阶段提交
InnoDB通过XA事务的两阶段提交机制协调二进制日志与重做日志:
Prepare阶段:重做日志写入完成
Commit阶段:二进制日志写入完成
5.3 安全配置推荐
# 最安全的数据持久化配置
innodb_flush_log_at_trx_commit = 1 # 每次事务提交都刷盘
sync_binlog = 1 # 每次事务都同步二进制日志
六、复制配置
6.1 备份方式对比
备份工具 | 类型 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
mysqldump | 逻辑备份 | 支持部分复制、表级过滤 | 速度慢、锁表影响业务 | 中小型数据库、特定表复制 |
XtraBackup | 物理备份 | 性能优秀、热备份、影响小 | 不支持部分复制、工具依赖 | 大数据量、全实例复制 |
部分复制配置示例:
replicate-do-table=db_name.table_name
6.2 【实验】后期有时间会出
如有问题或建议,欢迎在评论区中留言~