当前位置: 首页 > 科技观察

MySQLGroupReplicationMulti-Primary模式,你真的了解吗?

时间:2023-03-16 11:15:05 科技观察

MySQL数据库支持四种传统的事务隔离级别,分别是ReadUncommitted(RU)、ReadCommitted(RC)、RepeatableRead(RR)和Serializable(SRZ)。但是,对于MySQLGroupReplicationMulti-Primary模式,严格来说,其事务隔离级别是快照事务隔离级别(SnapshotIsolation,以下简称:SI)。今天江老师就来说说数据库的快照事务隔离级别。快照隔离概述很多DBA同学在面试的时候都会被问到事务的隔离级别,然后他们会说ReadUncommitted、ReadCommitted、RepeatableRead、Serializable。是的,但是四大事务隔离级别的定义江老师更喜欢称之为经典事务隔离级别,也就是ANSISQL92定义的事务隔离级别。ANSISQL92定义的事务隔离级别解决了脏读(dirtyread)、RepeatableRead(不可重复读)、Phatom(幻读)依次进行。当时的学术界认为,只要解决了这三个问题,那么交易就真正实现了隔离。最后推导出带有两阶段锁的Serializable事务隔离级别可以保证完全隔离。基本的序列化定理是格式良好的两阶段锁定保证了序列化。但!后来,HalBerenson和JimGray在1995年发表了一篇新论文《A critique of ANSI SQL Isolation levels》[1],批判了ANSISQL级别的事务隔离。在论文的摘要中,您可以看到以下内容:ANSISQL-92[MS,ANSI]根据现象定义隔离级别:脏读、不可重复读和幻影。本文表明,这些现象和ANSISQL定义无法描述几种流行的隔离级别,包括这些级别的标准锁定实现。调查现象的模糊性可以得出更清晰的定义;此外,引入了更好地表征隔离类型的新现象。定义。在论文的总结部分,您可以看到以下内容:综上所述,隔离级别的原始ANSISQL定义存在严重问题。可以说这篇论文基本上应该把JimGray放在他的书中《Transaction Processing: Concepts and Techniques》[2],对事务隔离级别的定义进行“彻头彻尾”的批判。论文大意是除了ANSISQL定义的三个并发问题,还有其他并发问题,比如LostUpdate(P4),ReadSkew(A5A),WriteSkew(A5B),NewPhantom(A3B)等。之前定义的事务隔离级别,SRZ除外,无法解析。然后论文引入了一个新的事务隔离级别SI,除了SRZ之外,它的隔离性比以前更好。这样的应用程序会发现快照隔离比任何一个都表现得更好:它避免了丢失更新异常、一些幻象异常(例如,由ANSISQL定义的异常),它从不阻塞只读事务,并且读者不阻塞更新。为了简洁起见,这里只是举一个ReadSkew问题的例子,看下面的测试用例:可以看到事务T1读取了事务T2修改的数据,所以不满足隔离要求。但是这种场景不在ANSISQL定义的DirtyRead、RepeatableRead和Phatom的范围内。上面的场景就是论文中定义的ReadSkew:A5AReadSkew假设事务T1读取x,然后第二个事务T2将x和y更新为新值并提交。如果现在T1读取y,它可能会看到不一致的状态,因此会产生不一致的状态作为输出。在历史方面,我们有异常:A5A:r1[x]...w2[x]...w2[y]...c2...r1[y]..(c1ora1)UnderRC和RR隔离级别,以上问题无法解决,只能通过设置隔离级别为SRZ。但是SRZ隔离级别需要遵循两级加锁,即加锁每条读记录可能会被写操作阻塞。因此,使用SRZ隔离级别后,数据库并发性能较差。但是SI事务隔离级别不会出现ReadSkew问题,读操作不会阻塞更改操作。简单的说,SI比SRZ有更好的隔离性和更好的性能,甚至可以匹敌RC事务隔离级别。BTW,论文中提到的(Basic)SI隔离级别也没有解决WriteSkew的问题。但是在后来的论文《Serializable isolation for snapshot databases》[3]中,SSI(SerializableSnapshotIsolation)完全满足了事务隔离的要求。快照隔离实现原理论文《A critique of ANSI SQL Isolation levels》对SI的实现原理进行了总体介绍。原理很简单,主要有以下几个主要流程:(1)当事务T1读取到第一条记录时,分配一个Start-Timestamp,这个值是单调递增的;(2)任何被事务修改的记录都会被写入快照,这样事务就需要访问这些历史记录版本;(3)当事务T1提交时,会得到一个Commit-Timestamp。事务T1可以提交的前提是没有其他事务T2在修改事务T1的任何变化记录。原文:只有在T1的执行间隔[Start-Timestamp,Commit-Timestamp]内没有其他事务T2写入T1也写入的数据时,事务才会成功提交。(4)如果事务提交时发生冲突,先提交哪个事务,则提交成功,这种机制称为:先提交胜。从上面的实现原理来看,SI本质上是一种乐观锁机制。读操作不会被写操作阻塞,只有在提交写操作时才会进行冲突检测。因此,如果大多数情况下每个事务的更新记录不冲突,那么SI隔离级别的性能是非常优秀的,即上面提到的性能并不逊色于RC。那么,SI是完美的吗?它的缺点是什么?其实在生产环境中,他的缺点更为致命。一方面,他需要假设在交易的大多数情况下更新的记录是不冲突的。如果出现热点,比如尖峰之类的场景,SI的性能会严重下降。另一方面,每条记录的快照需要以类似于RowVersion+Start-Timestamp的形式存储在内存中。如果有大事务,则需要更大的内存使用量。因此,支持SI隔离级别的数据库,如PostgreSQL数据库,需要设置内存使用率才能使用SSI隔离级别。当然,新版本的PG似乎已经解决了这个问题[3]。MGR和SI讲了这么多SI知识点,其实现在大家会发现MGRMulti-Primary模式的隔离级别本质上就是SI。首先,虽然MGRMulti-Primary模式是ShareNothing架构,但它允许数据在多个节点并发写入。我们需要把MGR集群看成是一个大型的数据库实例。其次,MGRMulti-Primary模式是一种乐观锁机制。当多个事务并发提交时,将在每个节点上进行全局冲突检测。如果在事务之间有更新同一行的记录,则回滚该事务。冲突检测的原理是基于WriteSet,回滚的原理还是遵循First-committed-wins。最后,MGR需要严格控制交易规模。当交易过大时,Certification_info会占用大量内存,导致系统不稳定。参数group_replication_transaction_size_limit用于控制事务的大小,类似于SI隔离级别的内存使用上限的控制。MySQL源码中也有SI实现的简要说明:综上所述,在以往的单实例数据库SI隔离级别中,事务提交时的冲突检测仅在单进程中完成。但是对于像MGRMulti-Primary这样的集群,在事务移交之前,会通过Paxos协议将Certification_info发送给MGR中的各个节点,然后进行冲突检测。其中,Certification_info是由组成的映射。typedefstd::unordered_mapCertification_info;同样,对于SI事务隔离级别,提交可能会失败。即在MGRMulti-Primary模式下,正常的commit可能会失败!!!第4行的错误3101(HY000):插件指示服务器回滚当前事务。一方面,在MGR中,事务提交失败不代表数据库失败,业务需要有重试逻辑(理解乐观锁机制)。另一方面,业务方要做好对上述错误码的监控。如果很多,说明你的MGRMulti-Primary模式使用姿势有很大问题。总结MySQLGroupReplicationMulti-Primary是迄今为止最伟大的关系型数据库产品,但是很多同学并不能充分发挥它的优势。这就好比拿一辆特斯拉ModelS当燃油车跑赛道,最后的成绩肯定不会理想。因此,理解SI隔离级别是理解MySQLGroupReplicationMulti-Primary的第一步,也是充分发挥MGR全部潜力的第一步。MGR,你准备好了吗?参考文献:[1]。https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf[2]。J.Gray和A.Reuter,“事务处理:概念和技术”[3]。https://courses.cs.washington.edu/courses/cse444/08au/544M/READING-LIST/fekete-sigmod2008.pdf[4]。https://drkp.net/papers/ssi-vldb12.pdf