设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 手机 数据 公司
当前位置: 首页 > 服务器 > 安全 > 正文

微信开源PhxSQL背后:强一致高可用分布式数据库的设计和实现哲学(5)

发布时间:2021-01-07 19:13 所属栏目:53 来源:网络整理
导读:图 4:事务生命周期状态转换 当一个事务只涉及到一个集合的数据时,称为本地事务,由这个集合的主机的本地事务管理器先使用本地严格2PL仲裁,然后将committing状态的事务通过原子广播发给其它备机. 当一个事务涉及到多

图 4:事务生命周期状态转换

当一个事务只涉及到一个集合的数据时,称为本地事务,由这个集合的主机的本地事务管理器先使用本地严格2PL仲裁,然后将committing状态的事务通过原子广播发给其它备机.

当一个事务涉及到多于一个集合的数据时,称为复合事务(complex transaction).

这个事务所涉及的某个数据集合的主机将committing事务状态,包括读集合(如果需要serializable级别隔离.这里的一个小优化是采用dummy row减少可能极其庞大的读集合)、写集合、以及committing状态,通过原子广播发给全组进行仲裁.Galera和MySQL Group Replication都只是校验写集合,因此不支持serializable级别事务隔离.

每台机器都可以通过本地事务状态和原子广播收到的消息,独立判定committing事务最终是提交还是终止.这种判定由原子广播的特性保证全局一致.

图 5:Deferred Update Replication和Certification-based Replication事务执行时序

强调一下:在机器通过原子广播进行数据同步时,事务的最终结果不能在广播前决定,而是在执行这条消息依赖的前置消息及这条消息后才能决定.这称为Deferred Update Replication推迟的更新复制或者Certification-based Replication.

这里有个重要特点需要注意:只有收到一条消息的所有前置消息后,这条消息和所有未执行的前置消息才能由事务管理器并发执行.因此,这里引入了一定的串行化.

原子广播的突出优点是在低延迟局域网有很高的吞吐率.

但同时原子广播有不小的按机器个数放大的网络延迟,在非低延迟网络会显著放大网络延迟.MySQL Group Replication使用的Corosync和Galera支持的Spread都是基于Totem这个成员管理和原子广播协议.

Totem是个为低延迟局域网设计的协议.在Totem中,所有机器组成一个环(ring).无论一台机器是否需要广播,令牌(token)在机器之间都按照环顺序传递.只有拿到令牌的机器才可以进行广播,即发出提交事务请求.因此在下一台机器收到上一台机器令牌的网络延迟期间,整个系统处于等待状态.

为了保证Safe Order Delivery,消息(实际是regular token,不是regular message)需要在环中循环两圈,才能知道是否可以执行,消息延迟是(4f+3)*RTT/2,其中(2f+1)是机器的数目、f表示容错的机器数.

在一个典型的两地三中心部署中,这导致一次事务写操作延迟极其高昂.例如一地两中心的网络延迟一般可以控制在2ms(单向),上海-深圳间网络延迟一般是15ms(单向),则一次事务写操作的网络延迟是64ms!

在两地三中心的配置中,PhxSQL的主和一个备一般分别在一地的两中心,另一个在异地.在通常情况下,master的Paxos一次写入只需一个accept,并且只等最快的备机返回.这时PhxSQL的写延迟只有4ms!

相比Paxos这类协议,原子广播还有一个缺陷.当任意一台机器宕机或者网络中断时,Totem此时会超时,在踢掉宕机的机器、重新确定组成员之前,整个集群的消息停止执行,即写操作暂停.

对于read-only事务,只有去数据集合的主机读取、或者昂贵地读取原子广播Quorum台机器、或者使用类似Spanner的TrueTime技术读取任一符合资格的机器,才能保证线性一致性.Galera节点间有延迟,并且只读事务在本地执行,不支持线性一致性.如果MySQL Group Replication支持线性一致性,请不吝告知.

了解基于原子广播的组内多主多写模式的原理和优缺点后,使用多写模式还需要根据业务仔细划分数据集,尽量减少公共数据的使用,同时处理好自增key的细节问题,以减少事务间的跨机冲突.

PhxSQL建立在开源的PhxPaxos基础上,感兴趣的读者可以用PhxPaxos方便实现原子广播插件,加载到MySQL中,从而支持多写.

如果不要read repeatable或者serializable级别隔离的事务,例如简单的key-value操作,同时通过lease机制保证线性一致性,是可以做到高效率多写的.但这就违反了PhxSQL完全兼容MySQL和最小侵入MySQL的原则.

2、为什么不支持分库分表?

分库分表也是个诱人的选择:可以平行无限扩展读写性能.分库分表就是分组,上个小节已经讨论了分布式事务的高昂成本.另外,为了保证完全兼容MySQL、支持全局事务和serializable级别事务隔离,不大改MySQL就支持sharding是非常困难的.

大改又违反了“最小侵入MySQL”原则,并且可能引入新的不兼容性.在应用不要求全局事务和serializable级别事务隔离情况下,感兴趣的读者可以把PhxSQL作为一容错的MySQL模块,在上层构建支持分库分表的系统.因为PhxSQL本身的容错性,这样做比在MySQL基础上直接构建要简单,无需关心每个sharding本身的出错.

如果以后有需求,PhxSQL团队也可能基于PhxSQL开发一个分库分表的新产品.当然,这个产品难以提供PhxSQL级别的兼容性.

3、为什么这么纠结于serializable级别事务隔离性,read repeatable级别很多时候已经够用了啊?

我们在设计原则中已经提到,为了完全兼容MySQL.我们认为一项好的技术是一项简单方便用户的技术,提供符合用户直觉预期、不用看太多注意事项的技术是我们的体贴.我们很诚恳,也是为了方便用户.我们不想说PhxSQL完全兼容MySQL,然后在不起眼的地方blabla列出好几页蝇头小字的例外.事实上,对于关键业务来说,serializable是必要的、read repeatable是不足的.read repeatable有个令人讨厌的write-skew异常[12].

举个例子.小薇在一个银行有两张信用卡,分别是A和B.银行给这两张卡总的信用额度是2000,即A透支的额度和B透支的额度相加必须不大于2000:A+B<=2000.

两个账户的扣款函数用事务执行分别是:

A账户扣款函数:

sub_A(amount_a):

begin transaction

if (A+B+amount_a <= 2000)

{ A += amount_a }

Commit

B账户扣款函数:

sub_B(amount_b):

begin transaction

if (A+B+amount_b <= 2000)

{ B += amount_b }

commit

假定现在A==1000,B==500.如果小薇是个黑客,同时用A账户消费300和B账户消费300,即amount_a == 400,amount_b == 300.那么这个数据库会发生什么事情呢?

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读