MySQL -- 主从复制的可靠性与可用性
Master-Master 主从切换
同步延时
- 主库A执行完成一个事务,写入binlog,记为
T1
- 然后传给从库B,从库B接收该binlog,记为
T2
- 从库B执行完成这个事务,记为
T3
- 同步延时:
T3-T1
- 同一个事务,在从库执行完成的时间和主库执行完成的时间之间的差值
SHOW SLAVE STATUS
中的Seconds_Behind_Master
Seconds_Behind_Master
- 计算方法
- 每个事务的
binlog
里面都有一个时间字段,用于记录该binlog
在主库上的写入时间 - 从库取出当前正在执行的事务的时间字段的值,计算它与当前系统时间点差值,得到
Seconds_Behind_Master
- 即
T3-T1
- 每个事务的
- 如果主库与从库的时间不一致,
Seconds_Behind_Master
会不会有误差?- 一般不会
- 在从库连接到主库时,会通过
SELECT UNIX_TIMESTAMP()
获取当前主库的系统时间 - 如果从库发现当前主库的系统时间与自己的不一致,在计算
Seconds_Behind_Master
会自动扣除这部分差值 - 但建立连接后,主库或从库又修改了系统时间,依然会不准确
- 在网络正常的情况下,
T2-T1
通常会非常小,此时同步延时的主要来源是**T3-T2
**- 从库消费
relaylog
的速度跟不上主库生成binlog
的速度
- 从库消费
延时来源
- 从库所在机器的性能要弱于主库所在的机器
- 更新请求对于IPOS的压力,在主库和从库上是无差别的
- 非对称部署:20个主库放在4个机器上,但所有从库放在一个机器上
- 主从之间可能会随时切换,现在一般都会采用相同规格的机器+对称部署
- 从库压力大
- 常见场景:管理后台的查询语句
- 从库上的查询耗费大量的CPU资源和IO资源,影响了同步速度,造成了同步延时
- 解决方案
- 一主多从,分担读压力,一般都会采用
- 通过
binlog
输出到外部系统,例如Hadoop
- 大事务
- 主库上必须等待事务执行完成后才会写入
binlog
,再传给从库 - 常见场景1:一次性删除太多数据(如归档的历史数据)
- 解决方案:控制每个事务删除的数据量,分多次删除
- 常见场景2:大表DDL
- 解决方案:
gh-ost
- 解决方案:
- 主库上必须等待事务执行完成后才会写入
- 从库的并行复制能力(后续展开)
切换策略
可靠性优先
切换过程一般由专门的HA
系统完成,存在不可用时间(主库A和从库B都处于只读状态)
- 判断从库B的
Seconds_Behind_Master
值,当小于某个值(例如5)才继续下一步 - 把主库A改为只读状态(
readonly=true
) - 等待从库B的
Seconds_Behind_Master
值降为0
- 把从库B改为可读写状态(
readonly=false
) - 把业务请求切换至从库B
可用性优先
不等主从同步完成,直接把业务请求切换至从库B,并且让从库B可读写,这样几乎不存在不可用时间,但可能会数据不一致
表初始化
1 | CREATE TABLE `t` ( |
插入数据
1 | INSERT INTO t (c) VALUES (4); |
MIXED
- 主库A执行完
INSERT c=4
,得到(4,4)
,然后开始执行主从切换 - 主从之间有5S的同步延迟,从库B会先执行
INSERT c=5
,得到(4,5)
,并且会把这个binlog
发给主库A - 从库B执行主库A传过来的
INSERT c=4
,得到(5,4)
- 主库A执行从库B传过来的
INSERT c=5
,得到(5,5)
- 此时主库A和从库B会有两行不一致的数据
ROW
- 采用
ROW
格式的binlog
时,会记录新插入行的所有字段的值,所以最后只会有一行数据不一致 - 主库A和从库B的同步线程都会报错并停止:
duplicate key error
小结
- 使用
ROW
格式的binlog
,数据不一致的问题更容易发现,采用MIXED
或STATEMENT
格式的binlog
,数据可能悄悄地不一致 - 主从切换采用可用性优先策略,可能会导致数据不一致,大多数情况下,优先选择可靠性优先策略
- 在满足数据可靠性的前提下,MySQL的可用性依赖于同步延时的大小(同步延时越小,可用性越高)
参考资料
《MySQL实战45讲》
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.