certification介绍
certification的作用为MYSQL多MASTER时,事务的冲突检测,也是MGR与之前的半同步复制的主要区别,在commit,写binlog之前加入了certify步骤(冲突检测),解决多MASTER时,可能导致数据不一致的问题。
我们考虑下面3个事务,T1,T2,T3,同时更新id=1 and c=0的记录, 如果在单库上执行由innodb完成事务冲突处理,事物一致性,是没有问题的
但如果在MYSQL多MASTER部署,T1,T2,T3分别在别不同的实例上执行,三个事务产生的冲突innodb就无能为力了,最3个事务执行完成后,c值为多少?
由于commit之后才能会binlog同步到其它库,三个update都可以执行成功,都更新了记录,但commit如果都能成功,三个事务都认为自己更新成功了,那么就产生了不一致的数据。
MGR 中 certification就是要解决这种问题。实际上T1,T2,commit会失败。
T1,T2 commit报错如下
ERROR 1180 (HY000): Got error 149 - ‘Lock deadlock; Retry transaction’ during COMMIT
certification实现
-
GTID分配
普通主从复制,GTID分配是 server_uuid:id(number)
MGR GTID分配与普通主从复制不同,每个mgr组统一分配 group_replication_group_name(uuid):id(number) -
冲突检测的单位
冲突检测的最小单位为行(暂时这么理解,不一定准确)
怎么唯一标识行?
索引名称+db名+db名长度+表名+表名长度+构成索引唯一性的每个列的值+值长度
所以使用MGR必须有主键 -
MGR的冲突检测
MYSQL 乐观执行,在事务执行时认为不会发生冲突,在commit时才会检查冲突,并最终完成(持久化)事务操作。
以上面的例子进行说明
00:00 T1 UPDATE ID=1的行,执行成功,ID=1 时间戳00:00
00:01 T2 UPDATE ID=1的行,执行成功,ID=1 时间戳00:00
00:02 T3 UPDATE ID=1的行,执行成功,ID=1 时间戳00:00
00:03 T3 COMMIT成功,ID=1的最终事务修改时间戳为00:03 ID=1 时间戳00:03
00:04 T1 COMMIT时,发现我00:00修改的数据,已经修其它事务修改(早于ID=1 时间戳00:03),操作的是旧的数据,发生冲突,回滚。
00:04 T1 COMMIT时,发现我00:01修改的数据,已经修其它事务修改(早于ID=1 时间戳00:03),操作的是旧的数据,发生冲突,回滚。
当然MYSQL MGR中实现的时间戳并不是时间,(多个节点中的时钟不同怎么办),MGR使用逻辑事务时间,dml或commit时的gtid_executed
使用gtid_executed 作为事务时间(执行事务之前获取当前的gtid_executed作为事务戳 snapshot version),进行示例(对group name(uuid)进行了简化)
00:00 T1 UPDATE ID=1的行,执行成功,ID=1 gtid_executed snapshot 1a55cda2:1-10
00:01 T2 UPDATE ID=1的行,执行成功,ID=1 gtid_executed snapshot 1a55cda2:1-10
00:02 T3 UPDATE ID=1的行,执行成功,ID=1 gtid_executed snapshot 1a55cda2:1-10
00:03 T3 COMMIT成功,ID=1的最终事务修改时间戳为00:03 ID=1 commit gtid_executed 1a55cda2:1-11
00:04 T1 COMMIT时,发现修改ID=1的记录snapshot gtid_executed 1a55cda2-9e7c-11ea-ae57-080027db8b10:1-10 是 commit gtid_executed 1a55cda2-9e7c-11ea-ae57-080027db8b10:1-11的真子集,也就是操作的数据是旧数据,发生冲突,回滚。
00:04 T1 COMMIT时,发现修改ID=1的记录snapshot gtid_executed 1a55cda2-9e7c-11ea-ae57-080027db8b10:1-10 是 commit gtid_executed 1a55cda2-9e7c-11ea-ae57-080027db8b10:1-11的真子集,也就是操作的数据是旧数据,发生冲突,回滚。
- certification_info
Certification_info是数据库状态机复制协议的核心组件。它实现了基于certification procedure实现冲突检测。
1、用于全局事物分配,Snapshot Isolation 给满足认证且可以提交给组中所有成员的事务分配逻辑时间戳,事务id。
2、是一个单调递增的计数器,在组中的所有成员中都是相同的。gtid_execute
3、用于生成snapshot version,还用于更新认证信息。
4、将事务中的数据行映射到事务在执行时看到的gtid_execute,即transaction snapshot version(事务在哪个版本上执行)
5、认证时事务携带的snapshot version,与certification_info中的进行比较,如果传入的snapshot version,是相同write set的已经certified transaction的子集,则认为当前 transaction在过期数据之上执行,认证失败。否则,此事务将被标记为certified并进入applier。同时更新Certification_info
typedef std::unordered_map<std::string, Gtid_set_ref *> Certification_info;
复制
write set(一组可以并应用,不会冲突的事务的集合),XXHASH64[索引名称+db名+db名长度+表名+表名长度+构成索引唯一性的每个列的值+值长度]
MAP(XXHASH64[索引名称+db名+db名长度+表名+表名长度+构成索引唯一性的每个列的值+值长度] Gtid_set)
- certification_info的清理
certification_info始终保存在内存中,随着事务的执行,certification_info会越来越大,占用大量内存,且影响认证效率,需要及时清理
当certification_info 中的snapshot version小于所有已经开始的事务,则可以被清理,因为事务的snapshot version>certification_info中的snapshot version,不会产生冲突。
清理规则待更新…