1,一段话总结
MySQL主从同步的核心就是binlog复制: 主库把写操作记到二进制日志 里,从库拉过来重放一遍,数据就同步了。
整个流程涉及三个线程配合:
1)主库的dump线程 :监听binlog变更,有新内容就推事件给从库
2)从库的I/O线程: 拉取主库数据,把收到的binlog写进本地的relay log
3)从库的**SQL线程:**读relay log,逐条执行SQL语句

2,扩展
2.1 三种复制模式
MySQL支持异步 、同步 、半同步 三种复制模式,区别在于主库什么时候给客户端返回响应:
| 复制模式 | 主库返回时机 | 性能 | 数据可靠性 |
|---|---|---|---|
| 异步复制 | 写完binlog立即返回 | 最高 | 最低,主库挂了数据可能丢失 |
| 同步复制 | 等所有从库确认 | 最差 | 最高 |
| 半同步机制 | 等至少N个从库确认 | 折中 | 较高 |
MySQL默认是异步复制,主库写完binlog就直接返回,压根不管从库有没有收到。好处是快,坏处是主库突然挂了,那些还没同步过去的数据就丢失了。
2.2 半同步复制
MySQL 5.5 引入了半同步复制插件,5.7做了增强。核心思路是折中:不用等所有从库,只要有一个从库确认收到就行。
sql
-- 主库开启半同步
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
-- 至少等 1 个从库确认
SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1;
比如3个从库,配置等1个确认,只要有一个从库说"收到了",主库就返回响应。这样只有那个最快的从库和主库同时挂掉,数据才会丢。
mysql 5.7还区分了两种半同步模式:
1)AFTER.COMMIT:主库先提交事务,再等从库确认。万一主库提交后、从库确认前主库挂了,新主库上没这条数据,但老主库的客户端已经收到成功响应了,造成数据不一致。
2)AFTER_SYNC:主库先等从库确认,再提交事务。这样主库挂了,新主库上一定有这条数据,更安全。
2.2 主从延迟问题
主从延迟是生产环境的老大难问题,常见原因:
1)从库机器配置比主库差,执行慢
2)从库承担了大量读请求或跑报表,资源被抢占
3)大事务,一个事务改几百万行,从库得等主库执行完才能开始重放
4)主库并发高,从库并行复制跟不上
监控延迟可以看 SHOW SLAVE STATUS 里的Seconds_Behind_Master,但这个值不一定准,因为它算的是relay log里最后一个事件的时间戳和当前时间的差值,网络抖动会影响。更靠谱的做法是用pt-heartbeat这类工具,往主库定时写时间戳,从库读出来算差值。
2.3 主库挂了,怎么把从库提升为主库?
答:先确认从库已经把relay log全部回放完,执行 STOP SLAVE 停掉复制,再RESET SLAVE ALL清掉主库信息。然后修改应用配置指向新主库,其他从库也要 CHANGE MASTER TO指向新主库。如果用了 MHA或Orchestrator这类工具,切换是自动的,它们会选延迟最小的从库提升,还会处理好各从库的 binlog位点对齐。(现在很多是云厂商提供的云数据库,这块简单了解下即可)