25-MySQL是怎么保证高可用的?
# 主备延迟
首先要了解的是主备切换,可能有以下几种情况。
- 主动运维动作。
- 软件升级。
- 主库所在机器计划下线。
- 主库所在机器掉电。
这样会首先带来一个情况是 “同步切换”,过程如下
- 主库完成一个事务写入 binlog,这个时候记住时刻为 T1;
- 之后传给备库,备库接收这个事务记为 T2;
- 备库完成这个事务的执行,记为 T3;
T1-T3 的差值就是 second_behind_master。这也就是所谓的主备延迟,主备延迟的最直接表现就是备库的 relay_log 的消费速度,比主库的 binlog 速度慢。
# 主备延迟来源
主要是以下几种情况可能会导致主备延迟。
有些部署条件下,备库的机器明显不如主库的配置高。
备库的压力太大了。
大事务。
对于第一点做对称部署,可能会解决这个问题,但是有时候会发现做了对称部署还是会有主备延迟。
那么这就是第二个问题了,因为上一章说备库主要用来提供读能力,比如运营类查询语句,所以很多人的想法就是主库上只跑业务,用来起比较克制,反而忽略的备库的压力,导致备库大量资源被消耗,造成了延迟。
这种情况可以用两种方式解决
- 一主多从。
- 通过缓存技术来分摊读压力,如 es、redis 等等。
这种情况还是不能完全解决,因为还有大事务会导致延迟。比如一个事务里执行了 10 分钟,那么备库就会晚 10 分钟。
- 典型大事务一:一次性不要用 delete 删除太多东西。有时候有些归档类的数据,开发人员会一次性删除掉大量历史数据,这就是典型的大事务场景,所以要控制每次删除的数量,分成多次删除完。
- 典型大事务二:大表的 DDL,这个推荐是 gh-ost 来做。
如果还有延迟情况那就有可能是备库的并行复制能力了。
# 可靠性优先策略
在双 M 的结构下,进行主备切换的步骤是,SBM 指的是 seconds_behind_master
- 判断备库的 SBM,如果小于某个值就下一步,否则就重试。
- 把主库设置成只读。
- 判断备库的 SBM 直到 0 为止。
- 把备库设置成可读写。
- 业务请求切备库。
可以看到在第二部的时候系统处于不可用的状态,因为两个都是只读,直到步骤 5 才能恢复。
这个过程中最耗时的是,步骤 3,也就是主库向备库传 binlog 备库执行的过程, 如果这个过程 N 分钟,那么就代表系统 N 分钟不可用。N 过大业务是不可接受的。
# 可用性优先策略
如果把步骤 4、5 放在最开始执行,也就是不等待主备同步,直接切换到备库,并且让备库可以读写,那么系统就没有不可用时间了。但是有更严重错误,就是数据不一致。
CREATE TABLE `t` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`c` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
2
3
4
5
比如说有个自增的 id,切主备同步延迟有 5 秒,有个时间在主库新增一条数据 (c=4),然后突然主备切换,在这 5 秒的过程中有个请求新增一条数据 (c=5) 到了备库,然后主备同步因为备库是先新增的,所以数据变成了 (1,5) 和 (2,4) 造成了数据不一致。
当然在 row 格式下会更加容易被发现,因为 row 就如上一章所说的会将 id 一起带上,那么就会抛出异常 duplicate key error 并停止,但是在 mixed 或者 statement 就会造成数据不一致的情况了。所以优先建议使用可靠性优先的方式。
但可靠性优先的方式异常切换过程中有会有系统不可用的时间,而这个时间完全依赖于主备延迟,比如主备有 30 分钟的延迟,那么主库掉电,进行主备切换,需要等到 SBM=0 才行,在这个过程中系统是完全不可用的。就算是让备库提供了只读也不行,因为 relay_log 没有完成,会导致客户端已经读取到的一些数据丢失,虽然在 relay_Log 执行完成后也能恢复,但在金融系统中这样的情况是绝对不能出现的。所以主备延迟的时间越长,可用性就越低。
# 上一章答案
出现循环复制的两种情况
- 主库在完成事务后,立刻修改了 server_id,然后等到备库传回来的时候发现 server_id 不一样了,认为是一个新的 binlog 然后就出了问题。
- 假设有三个主机,A 和 B 之间构成双主复制,然而有一条数据是在 C 上完成更新的,A 和 C 之间又是主备关系,那么 C 执行完成后会传一个 binlog 日志到 A,而里面的 server_id 是 C,A 执行完成后传给 B,但这个 binlog 日志中的 server_id 还是 C,就成为第一种情况了,A 认为还是一个新的 binlog 然后继续执行。