27-主库出问题了,从库怎么办?
# 基于位点的主备切换
先看这个张图,如果说要把 B 设置为 A‘的 slave,需要执行一段命令。
CHANGE MASTER TO
MASTER_HOST=$host_name
MASTER_PORT=$port
MASTER_USER=$user_name
MASTER_PASSWORD=$password
MASTER_LOG_FILE=$master_log_name
MASTER_LOG_POS=$master_log_pos
2
3
4
5
6
7
master_log_pos 这个参数就是所谓的同步位点,然而这个位置很难精准找到,只能取一个大概得位置。
- 首先要等待 A’完成 relay_log。
- 在 A' 上执行
show master status
获取到 A’上最新的 file 和 position。 - 取出 A 的故障时刻。
- 用 mysqlbinlog 工具解析 A’的 File 得到 T 时刻的位点。
那为什么说这个值不准确呢?
假设 A 在提交了一个新增事务后,binlog 已经同步给 A' 和 B 了,然后 A 突然断电。
那么由于 binlog 已经同步,A' 和 B 都有个新增的这条数据。若获取到的位点是 123,那么这个新增数据的位点一定在 123 之后。如果执行上述命令就会出现 Duplicate entry ‘id_of_R’ for key ‘PRIMARY’错误。
所以在通过位点切换的情况下,需要设置跳过这些错误。有两种方式。
- 主动跳过一个事务。
- 直接设置跳过哪些错误的参数。
# GTID
上述这种方式不推荐使用,因为太麻烦而且错误率高。了解一下就行。
GTID 的全称是全局事务 ID。格式是 GTID=server_uuid:gno
。
- server_uuid 是一个 MySQL 实例启动的时候自动生成的。
- gno 是一个整数,初始值为 1,每次提交的时候分配,提交后 + 1。
注意
gno 和 transaction_id 不是一个东西,transaction_id 是在事务执行的时候分配的,即使事务回滚也会递增。所以 GTID 往往是连续的。
GTID 有两种生成方式
- gtid_next=automatic,默认值,记录 binlog 的时候会加入一行 SET @@SESSION.GTID_NEXT=‘server_uuid:gno’; 然后添加到 GTID 集合中。
- set gtid_next='current_gtid’,指定 gtid 的值,但是有两种情况,如果指定的 gtid 已经在集合存在了,那么这个事务会被系统忽略。执行完成后如果需要执行下一个事务就要执行 set 命令,要么是 automatic 要么还是指定。然后添加到 GTID 集合中。
# 基于 GTID 的主备切换
基于现在这个时刻实例 A‘的 GTID 集合记为 seta,实例 B 的 GTID 集合记为 setB,实例 B 把 setb 发送给 A’,A’计算出两者的差值,就是判断出在 A’中但是不在 B 中的数据。
- 如果 A’不包含,表示 A’已经把 B 需要的数据删除了,直接返回错误。
- 如果包含,A’从 binlog 中取出不在 B 中的事务顺序发给 B。
# GTID 和 Online DDL
之前说过 Online DDL 在索引创建错误或者是新增一个索引的时候可以用,在主备情况下为了不影响主库的性能,可以在备库中进行 DDL,等到流量稳定后再切换,所以要把备库 binlog 先关掉,但是如果有个数据新增了或者修改了,没有记录 binlog 主从不就不一致了。
这里 GTID 就可以解决这个问题了,按照上面所述的步骤但是不需要关闭备库的 binlog,在备库 DDL 之后,获取出备库的执行 DDL 的 GTID 记为 uuid:1,然后到主库上执行 set GTID_NEX="uuid:1",然后开启 slave。
# 上一章答案
选择 WRITESET,因为 WRITESET 是通过判断事务之间是否有依赖关系,如果没有依赖关系可以并行执行。
题目上说的是插入,那么不存在操作同一行的情况,所以可以并行执行。
COMMIT_ORDER 的话所有事务只能在二进制文件中顺序执行,即便没有依赖关系。
WRITE_SESSION 的话会将同一个会话中的事务视作有依赖关系,题上又说到是单线程插入了很多数据那么这个效果和 COMMIT_ORDER 一致。