MySQL 主备
-
MySQL 能够成为现下最流行的开源数据库,binlog 功不可没
- binlog 可以用来归档,也可以用来做主备同步
- 几乎所有的高可用架构,都直接依赖于 binlog
-
MySQL 主备切换流程 — M-S 结构
- 虽然节点 B 没有直接被访问,但依然建议把节点 B(备库)设置成只读(readonly)模式
- 有时候一些运营类的查询语句会被放到备库上去查,设置为只读可以防止误操作
- 防止切换逻辑有 bug,比如切换过程中出现双写,造成主备不一致
- 可以用 readonly 状态,来判断节点的角色
- readonly 设置对超级 (super) 权限用户是无效的,而用于同步更新的线程,就拥有超级权限
- 虽然节点 B 没有直接被访问,但依然建议把节点 B(备库)设置成只读(readonly)模式
-
主备流程图
-
主库接收到客户端的更新请求后,执行内部事务的更新逻辑,同时写 binlog
-
备库 B 跟主库 A 之间维持了一个长连接,主库 A 内部有一个线程专门服务这个长连接
-
一个事务日志同步的完整过程
- 在备库 B 上通过 change master 命令,设置主库 A 的 IP、端口、用户名、密码、位置等
- 在备库 B 上执行 start slave 命令,这时候备库会启动两个线程
- 即上图中的 io_thread 和 sql_thread(io_thread 负责与主库建立连接
- 主库 A 校验完用户名密码后,开始按照备库 B 传过来的位置,从本地读取 binlog并发送
- 备库 B 拿到 binlog 后,写到本地文件,称为中转日志(relay log)
- sql_thread 读取中转日志,解析出日志里的命令,并执行
- 后来由于多线程复制方案的引入,sql_thread 演化成为了多个线程
-
binlog 的三种格式对比
- statement:binlog 里面记录的是 SQL 语句的原文(占用空间小
- row:binlog 里面记录的是 每一行数据修改的形式(可以避免主备不一致的场景
- 从恢复数据的角度上看,更推荐使用 row( mysqlbinlog 解析出来后直接发给 MySQL
- mixed:集大家之所长,可能导致主备不一致的SQL使用 row 格式,否则使用 statement
-
MySQL 主备切换流程 – 双 M 结构
-
节点 A 和 B 之间总是互为主备关系,切换的时不用修改主备关系
-
如何解决两个节点间的循环复制的问题
- 规定两个库的 server id 必须不同,如果相同,则它们之间不能设定为主备关系
- 备库接到 binlog 并在重放的过程中,生成与原 binlog 的 server id 相同的新的 binlog
- 每个库在收到从自己的主库发过来的日志后,先判断 server id(相同则丢弃
-
通过上述机制依然可能出现死循环的场景
-
在一个主库更新事务后,用命令 set global server_id=x 修改了 server_id ….
-
三节点循环复制
- binlog 上的 server_id 就是 B,binlog 传给节点 A,然后 A 和 A’搭建了双 M 结构…
- 这种三节点复制的场景,做数据库迁移的时候会出现
- 临时解决方式:CHANGE MASTER TO IGNORE_SERVER_IDS=(server_id_of_B);
-
-
如何保证高可用
-
在满足数据可靠性的前提下,MySQL 高可用系统的可用性,是依赖于主备延迟的
- 延迟的时间越小,在主库故障的时候,服务恢复需要的时间就越短,可用性就越高
-
主备延迟
- 数据同步有关的时间点主要包括以下三个
- 主库 A 执行完成一个事务,写入 binlog,我们把这个时刻记为 T1
- 之后传给备库 B,我们把备库 B 接收完这个 binlog 的时刻记为 T2
- 备库 B 执行完成这个事务,我们把这个时刻记为 T3
- 主备延迟:同一个事务在备库执行完成的时间和主库执行完成的时间之间的差值,也就是 T3-T1
- 执行 show slave status 命令后,显示的 seconds_behind_master 用于表示当前备库延迟了多少秒
- 计算方式(其实就是 T3-T1,时间精度是秒
- 每个事务的 binlog 里面都有一个时间字段,用于记录主库上写入的时间
- 计算方式(其实就是 T3-T1,时间精度是秒
- 数据同步有关的时间点主要包括以下三个