什么是 MySQL 的主从同步机制?它是如何实现的?
- 标签:后端、MySQL、数据库
🏛 业务架构师
主从同步是"读写分离"的物理基础,流程四步:
- 主库提交事务写 binlog(逻辑变更日志,statement/row 格式);
- 从库 IO 线程连上主库,主库 dump 线程推送 binlog 事件;
- 从库 IO 线程写入本地中继日志 relay log;
- 从库 SQL 线程(可并行)重放 relay log,数据达成一致。
异步复制是默认模式(主库不等从库确认),另有半同步(至少一个从库 ack 才返回客户端)与组复制。
业务架构视角的三个关键判断:
- 读写分离是性价比最高的扩容:读流量通常十倍于写,加从库水平扩读能力,业务无感——大促前加两台从库顶报表和列表流量,是标准动作;
- 延迟是必然的,方案要围绕它设计:核心矛盾是"写后立读"——用户改完昵称刷新页面还是旧数据、支付成功页查不到订单,全是主从延迟的客诉。对策分级:关键读强制走主(金额、状态类,用注解/AOP 标记路由)、写后短时间窗口内读主、或"写后缓存标记";
- 复制模式按资损定价:异步复制主库宕机可能丢最后一批事务,支付库必须半同步起步;报表库异步足够。
引申一句:binlog 这条链路还是数据中台的源头(Canal 订阅同步 ES/数仓),主从机制养活了整条数据供应链,它 SLA 的价值远超"备份"本身。
🏗 系统架构师
主从同步是 MySQL 高可用与读写分离的基石,机制我按数据流讲:
复制流程:
- 主库提交事务时写 binlog(逻辑日志,记数据变更);
- 从库 IO 线程建立连接,主库 dump 线程推送 binlog 事件(也可以从库拉取);
- 从库 IO 线程把事件写入本地中继日志 relay log;
- 从库 SQL 线程(可多线程)读取 relay log 重放,数据达到一致。
两种复制格式:statement 记 SQL 语句(量小但有不一致风险,如 now()、limit);row 记行变更(体积大但确定性强,生产默认);mixed 混合。
三种复制模式:异步(默认,主不等从,可能丢数据)、半同步(至少一个从收到 ack 才返回提交,RDS 默认,兼顾性能与可靠性)、GTID 模式(事务全局编号,自动定位位点,搭从库和故障切换的标准姿势)。
架构用途:主写从读分摊读压力(注意复制延迟对"写后立读"的影响,必要时强制走主);从库做备份、异步任务、分析查询,隔离脏负载。我用 MHA/Orchestrator 或云上高可用做自动切换,切换的 RPO/RTO 取决于复制模式选型。
💻 全栈开发专家
主从同步是基于 binlog 的异步复制,三线程协作:
text
主库:客户端提交事务 → 写 binlog → binlog dump 线程推送日志事件给从库
从库:IO 线程接收 → 写入 relay log(中继日志)
SQL 线程(可多线程 MTS)重放 relay log → 数据变更关键参数与形态:
log_bin开启、server_id全局唯一、主库建复制账号授REPLICATION SLAVE;CHANGE MASTER TO MASTER_HOST=..., MASTER_AUTO_POSITION=1(GTID 模式,8.0 推荐,切换从库方便);- 半同步(
rpl_semi_sync):至少 1 个从库 ack binlog 才返回提交,降低丢失窗口,代价是 RT。
我处理过的坑:
- 大事务:一条 update 百万行,从库单线程重放卡几分钟,延迟暴涨——拆批 +
slave_parallel_workers并行复制。 - 从库写:有人误连从库改数据,数据漂移且不自愈,从库要
read_only=ON+super_read_only。 - 复制过滤:
replicate-ignore-db配错导致表缺失,搭建时核对SHOW SLAVE STATUS的过滤规则。
延迟监控看 Seconds_Behind_Master(粗糙,精确用 GTID/pt-heartbeat)。