摘要
上一章探讨了咱们为什么要做PhxSQL和为什么这样做PhxSQL。这里咱们次要谈谈为什么不做某些个性。舍得舍得,有舍才有得。CAP通知咱们只能三选二,俗话通知咱们天下没有收费的午餐。每个个性除了本身提供的性能,也有其代价。为了保障强统一的线性一致性、高可用、serializable级别事务隔离、齐全兼容MySQL、和最小侵入MySQL,PhxSQL放弃了一些个性。
注释
7. Why Not?
7.1. 为什么不反对多写?
多写想想就很迷人。多写能够充分利用每台机器写时须要的资源。例如某些写操作可能十分消耗CPU,多写能够把写操作扩散在各台机器上,充分利用各个机器的CPU资源,极大进步写入的性能。多写使得换主没有存在的必要,也就没有换主时可能存在的不可写工夫窗问题。多写还使得客户端能够就近写入,缩小跨数据中心写入带来的网络提早。
多写有两种:大家熟知的分shard或者组,各shard或者组间并行写入,以Google Spanner[8]为典型代表;在shard或者组内并行,以Galera和MySQL Group Replication为代表。
7.1.1. 组间多写
组间多写是把数据分成多个不相交的shard,每个组的机器负责一个shard 。当一个事务波及的数据(读汇合和或写汇合)都在某个组时,这种事务称为本地事务。当一个事务波及的数据分布在超过一个组时,这种事务称为分布式事务。
本地事务能够在本组独立执行,组之间不须要任何通信。为了缩小事务抵触带来的性能升高,个别都是由组内leader执行本地事务,通过Paxos等一致性协定保障组内机器的数据统一[8]。各个组间并行执行本地事务,能够极大进步本地型事务的写性能。
组间多写最大的妨碍是分布式事务,而分布式事务是十分低廉的。在SQL的模型中,为了实现read repeatable级别的事务隔离,事务管理器须要查看两个并发事务的写数据集是否抵触;为了达到serializable级别的事务隔离,事务管理器须要查看两个并发事务的读数据集和写事务集是否抵触[10]。这个别通过严格两阶段锁(strict two-phase locking,严格2PL)和/或者多版本并发管制MVCC实现。当这些数据集跨组时,就波及到跨组的机器通信。
一个组同时遇到本地事务和分布式事务时,在本组须要依据事务的隔离级别,由事务管理器仲裁执行。
以Google Spanner为例,一个波及两个机器组(Spanner中的组是指Paxos组)事务就须要在coordinator leader和non-coordinator-participant leader之间两次通信,前者组内还波及一次Paxos写操作,后者组内再加两次Paxos写操作[8,Sec. 4.2.1 Read-Write Transactions]。当跨机房部署时,机器之间的网络提早使得通信代价更加昂扬。Spanner为了缩小这种低廉的跨组事务,要求所有数据都必须有Primary key,并且其它数据尽量挂接在Primary key上面,使得事务尽量在一个组内、且由组内leader执行。
7.1.2. 组内多主多写
组内多主多写时每个机器都有残缺的数据,但这份数据分成不相交的逻辑汇合,每个机器负责一个汇合的写入。这台机器称为这个汇合的主机,这个汇合称为这个主机负责的数据,其它机器称为这个汇合的备机。客户端将写操作发到所波及数据的主机,由主机通过atomic broadcast原子播送将更新申请发送给组内所有的机器,包含主机自身[9]。Galera和MySQL Group Replication都是采纳这种办法。
图 3:组内多主多写架构[9]
原子播送具备3个个性:
i) 如果一台机器执行一条音讯所带的更新命令,那么所有的其它机器都执行这条命令(delivered)。这里“执行”指的是原子播送层将音讯交给下层,实在的执行时刻由下层决定。在数据库中,这个下层个别是并发事务管理器,它决定这些音讯的实在执行程序。
ii) 所有机器以雷同的程序执行命令。
iii) 如果一台机器胜利播送了一条音讯,那么最终所有机器都将执行这条音讯。
应用原子播送后,事务的生命周期从prepare->committed/aborted扭转为prepare->committing->committed/aborted。
图 4:事务生命周期状态转换[9]
当一个事务只波及到一个汇合的数据时,称为本地事务,由这个汇合的主机的本地事务管理器先应用本地严格2PL仲裁,而后将committing状态的事务通过原子播送发给其它备机。
当一个事务波及到多于一个汇合的数据时,称为复合事务(complex transaction)。这个事务所波及的某个数据汇合的主机将committing事务状态,包含读汇合(如果须要serializable级别隔离。这里的一个小优化是采纳dummy row缩小可能极其宏大的读汇合[10])、写汇合、以及committing状态,通过原子播送发给全组进行仲裁。Galera和MySQL Group Replication都只是校验写汇合,因而不反对serializable级别事务隔离[18]。
每台机器都能够通过本地事务状态和原子播送收到的音讯,独立断定committing事务最终是提交还是终止。这种断定由原子播送的个性保障全局统一。
图 5:Deferred Update Replication和Certification-based Replication事务执行时序[11]
强调一下:在机器通过原子播送进行数据同步时,事务的最终后果不能在播送前决定,而是在执行这条音讯依赖的前置音讯及这条音讯后能力决定。这称为Deferred Update Replication9推延的更新复制或者Certification-based Replication[11]。这里有个重要特点须要留神:只有收到一条音讯的所有前置音讯后,这条音讯和所有未执行的前置音讯能力由事务管理器并发执行。因而,这里引入了肯定的串行化。
原子播送的突出长处是在低提早局域网有很高的吞吐率。
但同时原子播送有不小的按机器个数放大的网络提早,在非低提早网络会显著放大网络提早。MySQL Group Replication应用的Corosync[16]、Galera[15]默认应用的gcomm和反对的Spread[17]都是基于Totem[13]这个成员治理和原子播送协定。
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[8]技术读取任一合乎资格的机器,能力保障线性一致性。Galera节点间有提早,并且只读事务在本地执行,不反对线性一致性[15]。如果MySQL Group Replication反对线性一致性,请不吝告知。
理解基于原子播送的组内多主多写模式的原理和优缺点后,应用多写模式还须要依据业务认真划分数据集,尽量减少公共数据的应用,同时解决好自增key等细节问题,以缩小事务间的跨机抵触。
PhxSQL建设在开源的PhxPaxos根底上,感兴趣的读者能够用PhxPaxos不便实现原子播送插件,加载到MySQL中,从而反对多写。
如果不要read repeatable或者serializable级别隔离的事务,例如简略的key-value操作,同时通过lease机制保障线性一致性,是能够做到高效率多写的。但这就违反了PhxSQL齐全兼容MySQL和最小侵入MySQL的准则。
7.2. 为什么不反对分库分表?
分库分表也是个迷人的抉择:能够平行有限扩大读写性能。分库分表就是分组,上个大节曾经探讨了分布式事务的昂扬老本。另外,为了保障齐全兼容MySQL、反对全局事务和serializable级别事务隔离,不大改MySQL就反对sharding是十分艰难的。大改又违反了“最小侵入MySQL”准则,并且可能引入新的不兼容性。在利用不要求全局事务和serializable级别事务隔离状况下,感兴趣的读者能够把PhxSQL作为一容错的MySQL模块,在下层构建反对分库分表的零碎。因为PhxSQL自身的容错性,这样做比在MySQL根底上间接构建要简略,无需关怀每个sharding自身的出错。如果当前有需要,PhxSQL团队也可能基于PhxSQL开发一个分库分表的新产品。当然,这个产品难以提供PhxSQL级别的兼容性。
7.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账户生产400和B账户生产300,即amount_a == 400,amount_b == 300。那么这个数据库会产生什么事件呢?
如果是read repeatable级别隔离,sub_a和sub_b都会同时胜利!最初A和B账户的透支额别离是A=1000+400=1400,B=500+300=800,总的透支额A+B=1400+800=2200>2000,超过了银行授予的额度!如果不是信用卡的两笔小生产,而是两笔大额转账,那么银行怎么办?
如果是serializable级别隔离,则sub_a和sub_b只有一个胜利。具体分析有趣味的读者能够本人实现。
7.4. 为什么不把显著晋升MySQL性能作为一个次要指标?
事实上,PhxSQL曾经显著晋升了MySQL主备的写入性能。与semi-sync比,在测试环境中,PhxSQL的写入性能比semi-sync高16%到25%以上。读性能持平。这是在满足齐全兼容MySQL和最小侵入MySQL准则下所能取得的后果。鉴于PhxSQL对MySQL的改变是如此之小,对性能有高要求的读者,能够不便地把PhxSQL中的MySQL换成其它高性能版本,取得更高性能。
7.5. 为什么编译时不反对C++11以下规范?
作为酷爱新技术的码农,咱们真的很喜爱C++11中期待已久、激动人心的新个性,例如极大加强的模板、lambda表达式、右值和move表达式、多线程内存模型等,这将C++带入了一个新的时代,大大提高了码农搬砖的速度、编码的正确性、和程序的性能。有了C++11,PhxSQL的开发效率进步了很多。
8. 与Galera及MySQL Group replication的比拟
参见7.1.2大节。
论断
PhxSQL是一个齐全兼容MySQL,提供与Zookeeper雷同强一致性和可用性的MySQL集群。
感激大家看完这么长的一篇文章。心愿大家多浏览PhxSQL源码,多提技术性意见,甚至成为源码贡献者!
参考
- M.P. Herlihy and J. M. Wing. Linearizability: a correctness condition for concurrent objects. ACM Transactions on Programming Languages and Systems (TOPLAS), Volume 12 Issue 3, July 1990, Pages 463-492.
- L. Lamport. How to make a multiprocessor computer that correctly executes multiprocess programs. IEEE Trans. Computer. C-28,9 (Sept. 1979), 690-691.
- P. Hunt, M. Konar, F. P. Junqueira, and B. Reed. ZooKeeper: wait-free coordination for Internet-scale systems. USENIXATC'10, 2010.
- L. Lamport. Paxos Made Simple. ACM SIGACT News (Distributed Computing Column) 32, 4 (Whole Number 121, December 2001) 51-58.
- D. Ongaro and J. Ousterhout. In search of an understandable consensus algorithm. USENIX ATC ’14, 2014.
- B. M. Oki and B.H. Liskov. Viewstamped replication: a New primary copy method to support highly-available distributed systems. PODC’88, 8-17, 1988.
- T. Chandra, R. Griesemer, and J. Redstone. Paxos made live – an engineering perspective. PODC’07, 2007.
- J. C. Corbett, J. Dean, M. Epstein, and etc. Spanner: Google's Globally-Distributed Database. OSDI'12, 2012.
- F. Pedone, R. Guerraoui, and A. Schiper. The database state machine approach. Journal of Distributed and Parallel Databases and Technology, 14:71–98, 2002
- V. Zuikeviciute and F. Pedone. Revisiting the database state machine approach. VLDB Workshop on Design, Implementation, and Deployment of Database Replication. 2005.
- Certification-based Replication. Visited at 2016/9/5.
- Snapshot isolation. Visited at 2016/9/5.
- Y. Amir, L. E. Moser, P. M. Melliar-smith, D. A. Agarwal, and P. Ciarfella. The totem single ring ordering and membership protocol. ACM Transactions on Computer Systems. 13 (4): 311–342.
- http://downloads.mysql.com/presentations/innovation-day-2016/Session_7_MySQL_Group_Replication_for_High_Availability.pdf. Visited at 2016/9/5.
- Replication API. Visited at 2016/9/5.
- Corosync by corosync. Visited at 2016/9/5.
- http://www.spread.org/. Visited at 2016/9/5.
- Isolation Levels. Visited at 2016/9/5
- L. Lamport. Fast Paxos. Technical Report, MSR-TR-2005-112.
- I. Moraru, D. G. Andersen, and M. Kaminsky. There is more consensus in egalitarian parliaments. SOSP’13, 2013.
- GitHub - tencent-wechat/phxpaxos: C++ Paxos library that has been used in Wechat production environment..
OpenIMgithub开源地址:
https://github.com/OpenIMSDK/...
OpenIM官网 :https://www.rentsoft.cn
OpenIM官方论坛:https://forum.rentsoft.cn/
更多技术文章:
开源OpenIM:高性能、可伸缩、易扩大的即时通讯架构
https://forum.rentsoft.cn/thr...
【OpenIM原创】简略轻松入门 一文解说WebRTC实现1对1音视频通信原理
https://forum.rentsoft.cn/thr...