数据一致性-分区可用性-性能——多副本强同步数据库系统实现之我见

3月 27th, 2015

新浪微博:@何_登成

1    背景    1

2    问题一:数据一致性    3

3    问题二:分区可用性    6

4    问题三:性能    8

5    总结    10

6    问题四:一个极端场景的分析    10

 

  1. 背景

 

00

最近,@阿里正祥(阳老师)发了上面的一条微博,谁知一石激起千层浪,国内各路数据库领域的朋友在此条微博上发散出无数新的话题,争吵有之,激辩有之,抨击有之,不一而足。总体来说,大家重点关注其中的一点:

在不使用共享存储的情况下,传统RDBMS(例如:Oracle/MySQL/PostgreSQL等),能否做到在主库出问题时的数据零丢失。

这个话题被引爆之后,我们团队内部也经过了激烈的辩论,多方各执一词。辩论的过程中,差点就重现了乌克兰议会时场景…

02

庆幸的是,在我的铁腕统治之下,同学们还是保持着只关注技术,就事论事的撕逼氛围,没有上升到相互人身攻击的层次。激辩的结果,确实是收获满满,当时我就立即发了一条微博,宣泄一下自己愉悦的心情J

01

微博发出之后,也有一些朋友回复是否可以将激辩的内容写出来,独乐乐不如众乐乐。我一想也对,强数据同步,数据一致性,性能,分区可用性,Paxos,Raft,CAP等一系列知识,我也是第一次能够较好的组织起来,写下来,一来可以加深自己的印象,二来也可以再多混一点虚名,何乐而不为J

这篇博客文章接下来的部分,将跳出任何一种数据库,从原理的角度上来分析下面的几个问题:

  • 问题一:数据一致性。在不使用共享存储的情况下,传统RDBMS(例如:Oracle/MySQL/PostgreSQL等),能否做到在主库出问题时的数据零丢失。
  • 问题二:分区可用性。有多个副本的数据库,怎么在出现各种问题时保证系统的持续可用?
  • 问题三:性能。不使用共享存储的RDBMS,为了保证多个副本间的数据一致性,是否会损失性能?如何将性能的损失降到最低?
  • 问题四:一个极端场景的分析

  1. 问题一:数据一致性

 

问:脱离了共享存储,传统关系型数据库就无法做到主备强一致吗?

答:我的答案,是No。哪怕不用共享存储,任何数据库,也都可以做到主备数据的强一致。Oracle如此,MySQL如此,PostgreSQL如此,OceanBase也如此。

如何实现主备强一致?大家都知道数据库中最重要的一个技术:WAL(Write-Ahead-Logging)。更新操作写日志(Oracle Redo Log,MySQL Binlog等),事务提交时,保证将事务产生的日志先刷到磁盘上,保证整个事务的更新操作数据不丢失。那实现数据库主备数据强一致的方法也很简单:

  1. 事务提交的时候,同时发起两个写日志操作,一个是将日志写到本地磁盘的操作,另一个是将日志同步到备库并且确保落盘的操作;
  2. 主库此时等待两个操作全部成功返回之后,才返回给应用方,事务提交成功;

整个事务提交操作的逻辑,如下图所示:

1 redo log同步

上图所示,由于事务提交操作返回给应用时,事务产生的日志在主备两个数据库上都已经存在了,强同步。因此,此时主库Crash的话,备库提供服务,其数据与主库是一致的,没有任何事务的数据丢失问题。主备数据强一致实现。用过Oracle的朋友,应该都知道Oracle的Data Guard,可工作在 最大性能,最大可用,最大保护 三种模式下,其中第三种 最大保护 模式,采用的就是上图中的基本思路。

实现数据的强同步实现之后,接下来到了考虑可用性问题。现在已经有主备两个数据完全一致的数据库,备库存在的主要意义,就是在主库出故障时,能够接管应用的请求,确保整个数据库能够持续的提供服务:主库Crash,备库提升为主库,对外提供服务。此时,又涉及到一个决策的问题,主备切换这个操作谁来做?人当然可以做,接收到主库崩溃的报警,手动将备库切换为主库。但是,手动的效率是低下的,更别提数据库可能会随时崩溃,全部让人来处理,也不够厚道。一个HA(High Availability)检测工具应运而生:HA工具一般部署在第三台服务器上,同时连接主备,当其检测到主库无法连接,就切换备库,很简单的处理逻辑,如下图所示:

2 HA

HA软件与主备同时连接,并且有定时的心跳检测。主库Crash后,HA探测到,发起一个将备库提升为主库的操作(修改备库的VIP或者是DNS,可能还需要将备库激活等一系列操作),新的主库提供对外服务。此时,由于主备的数据是通过日志强同步的,因此并没有数据丢失,数据一致性得到了保障。

有了基于日志的数据强同步,有了主备自动切换的HA软件,是不是就一切万事大吉了?我很想说是,确实这个架构已经能够解决90%以上的问题,但是这个架构在某些情况下,也埋下了几个比较大的问题。

首先,一个一目了然的问题,主库Crash,备库提升为主库之后,此时的数据库是一个单点,原主库重启的这段时间,单点问题一直存在。如果这个时候,新的存储再次Crash,整个系统就处于不可用状态。此问题,可以通过增加更多副本,更多备库的方式解决,例如3副本(一主两备),此处略过不表。

其次,在主备环境下,处理主库挂的问题,算是比较简单的,决策简单:主库Crash,切换备库。但是,如果不是主库Crash,而是网络发生了一些问题,如下图所示:

3 network partition

若Master与Slave之间的网络出现问题,例如:断网,网络抖动等。此时数据库应该怎么办?Master继续提供服务?Slave没有同步日志,会数据丢失。Master不提供服务?应用不可用。在Oracle中,如果设置为 最大可用 模式,则此时仍旧提供服务,允许数据不一致;如果设置为 最大保护 模式,则Master不提供服务。因此,在Oracle中,如果设置为 最大保护 模式,一般建议设置两个或以上的Slave,任何一个Slave日志同步成功,Master就继续提供服务,提供系统的可用性。

网络问题不仅仅出现在Master和Slave之间,同样也可能出现在HA与Master,HA与Slave之间。考虑下面的这种情况:

4 network partition

HA与Master之间的网络出现问题,此时HA面临两个抉择:

  1. HA到Master之间的连接不通,认为主库Crash。选择将备库提升为主库。但实际上,只是HA到Master间的网络有问题,原主库是好的(没有被降级为备库,或者是关闭),仍旧能够对外提供服务。新的主库也可以对外提供服务。两个主库,产生双写问题,最为严重的问题
  2. HA到Master之间的连接不通,认为是网络问题,主库未Crash。HA选择不做任何操作。但是,如果这时确实是主库Crash了,HA不做操作,数据库不对外提供服务。双写问题避免了,但是应用的可用性受到了影响。

最后,数据库会出现问题,数据库之间的网络会出现问题,那么再考虑一层,HA软件本身也有可能出现问题。如下图所示:

5 HA Crash

如果是HA软件本身出现了问题,怎么办?我们通过部署HA,来保证数据库系统在各种场景下的持续可用,但是HA本身的持续可用谁来保证?难道我们需要为HA做主备,然后再HA之上再做另一层HA?一层层加上去,子子孙孙无穷尽也 … …

其实,上面提到的这些问题,其实就是经典的分布式环境下的一致性问题(Consensus),近几年比较火热的Lamport老爷子的Paxos协议,Stanford大学最近发表的Raft协议,都是为了解决这一类问题。(对Raft协议感兴趣的朋友,可以再看一篇Raft的动态演示PPT:Understandable Distributed Consensus

 

 

  1. 问题二:分区可用性

 

前面,我们回答了第一个问题,数据库如果不使用共享存储,能否保证主备数据的强一致?答案是肯定的:可以。但是,通过前面的分析,我们又引出了第二个问题:如何保证数据库在各种情况下的持续可用?至少前面提到的HA机制无法保证。那么是否可以引入类似于Paxos,Raft这样的分布式一致性协议,来解决上面提到的各种问题呢?

答案是可以的,我们可以通过引入类Paxos,Raft协议,来解决上面提到的各类问题,保证整个数据库系统的持续可用。考虑仍旧是两个数据库组成的主备强一致系统,仍旧使用HA进行主备监控和切换,再回顾一下上一节新引入的两个问题:

  1. HA软件自身的可用性如何保证?
  2. 如果HA软件无法访问主库,那么这时到底是主库Crash了呢?还是HA软件到主库间的网络出现问题了呢?如何确保不会同时出现两个主库,不会出现双写问题?
  3. 如何在解决上面两个问题的同时,保证数据库的持续可用?

为了解决这些问题,新的系统如下所示:

6 paxos + 2副本

相对于之前的系统,可以看到这个系统的复杂性明显增高,而且不止一成。数据库仍旧是一主一备,数据强同步。但是除此之外,多了很多变化,这些变化包括:

  1. 数据库上面分别部署了HA Client;
  2. 原来的一台HA主机,扩展到了3台HA主机。一台是HA Master,其余的为HA Participant;
  3. HA主机与HA Client进行双向通讯。HA主机需要探测HA Client所在的DB是否能够提供服务,这个跟原有一致。但是,新增了一条HA Client到HA主机的Master Lease通讯。

这些变化,能够解决上面的两个问题吗?让我们一个一个来分析。首先是:HA软件自身的可用性如何保证?

从一台HA主机,增加到3台HA主机,正是为了解决这个问题。HA服务,本身是无状态的,3台HA主机,可以通过Paxos/Raft进行自动选主。选主的逻辑,我这里就不做赘述,不是本文的重点,想详细了解其实现的,可以参考互联网上洋洋洒洒的关于Paxos/Raft的相关文章。总之,通过部署3台HA主机,并且引入Paxos/Raft协议,HA服务的高可用可以解决。HA软件的可用性得到了保障。

第一个问题解决,再来看第二个问题:如何识别出当前是网络故障,还是主库Crash?如何保证任何情况下,数据库有且只有一个主库提供对外服务?

通过在数据库服务器上部署HA Client,并且引入HA Client到HA Master的租约(Lease)机制,这第二个问题同样可以得到完美的解决。所谓HA Client到HA Master的租约机制,就是说图中的数据库实例,不是永远持有主库(或者是备库)的权利。当前主库,处于主库状态的时间是有限制的,例如:10秒。每隔10秒,HA Client必须向HA Master发起一个新的租约,续租它所在的数据库的主库状态,只要保证每10秒收到一个来自HA Master同意续租的确认,当前主库一直不会被降级为备库。

第二个问题,可以细分为三个场景:

  • 场景一:主库Crash,但是主库所在的服务器正常运行,HA Client运行正常

    主库Crash,HA Client正常运行。这种场景下,HA Client向HA Master发送一个放弃主库租约的请求,HA Master收到请求,直接将备库提升为主库即可。原主库起来之后,作为备库运行。

  • 场景二:主库所在的主机Crash。(主库和HA Client同时Crash)

    此时,由于HA Client和主库同时Crash,HA Master到HA Client间的通讯失败。这个时候,HA Master还不能立即将备库提升为主库,因为区分不出场景二和接下来的场景三(网络问题)。因此,HA Master会等待超过租约的时间(例如:12秒),如果租约时间之内仍旧没有续租的消息。那么HA Master将备库提升为主库,对外提供服务。原主库所在的主机重启之后,以备库的状态运行。

  • 场景三:主库正常,但是主库到HA Master间的网络出现问题

    对于HA Master来说,是区分不出场景二和场景三的。因此,HA Master会以处理场景二同样的逻辑处理场景三。等待超过租约的时间,没有收到续租的消息,提升原备库为主库。但是在提升备库之前,原主库所在的HA Client需要做额外的一点事。原主库HA Client发送给HA Master的续租请求,由于网络问题,一直没有得到响应,超过租约时间,主动将本地的主库降级为备库。如此一来,待HA Master将原备库提升为主库时,原来的主库已经被HA Client降级为备库。双主的情况被杜绝,应用不可能产生双写

通过以上三个场景的分析,问题二同样在这个架构下被解决了。而解决问题二的过程中,系统最多需要等待租约设定的时间,如果租约设定为10秒,那么出各种问题,数据库停服的时间最多为10秒,基本上做到了持续可用。这个停服的时间,完全取决于租约的时间设置。

到这儿基本可以说,要实现一个持续可用(分区可用性保证),并且保证主备数据强一致的数据库系统,是完全没问题的。在现有数据库系统上做改造,也是可以的。但是,如果考虑到实际的实现,这个复杂度是非常高的。数据库的主备切换,是数据库内部实现的,此处通过HA Master来提升主库;通过HA Client来降级备库;保证数据库崩溃恢复后,恢复为备库;通过HA Client实现主库的租约机制;实现HA主机的可用性;所有的这些,在现有数据库的基础上实现,都有着相当的难度。能够看到这儿,而且有兴趣的朋友,可以针对此问题进行探讨J

 

  1. 问题三:性能

 

数据一致性,通过日志的强同步,可以解决。分区可用性,在出现任何异常情况时仍旧保证系统的持续可用,可以在数据强同步的基础上引入Paxos/Raft等分布式一致性协议来解决,虽然这个目前没有成熟的实现。接下来再让我们来看看一个很多朋友都很感兴趣的问题:如何在保证强同步的基础上,同时保证高性能?回到我们本文的第一幅图:

1 redo log同步

为了保证数据强同步,应用发起提交事务的请求时,必须将事务日志同步到Slave,并且落盘。相对于异步写Slave,同步方式多了一次Master到Slave的网络交互,同时多了一次Slave上的磁盘sync操作。反应到应用层面,一次Commit的时间一定是增加了,具体增加了多少,要看主库到备库的网络延时和备库的磁盘性能。

为了提高性能,第一个很简单的想法,就是部署多个Slave,只要有一个Slave的日志同步完成返回,加上本地的Master日志也已经落盘,提交操作就可以返回了。多个Slave的部署,对于消除瞬时的网络抖动,非常有效果。在Oracle的官方建议中,如果使用最大保护模式,也建议部署多个Slave,来最大限度的消除网络抖动带来的影响。如果部署两个Slave,新的部署架构图如下所示:

7 paxos+db

新增一个Slave,数据三副本。两个Slave,只要有一个Slave日志同步完成,事务就可以提交,极大地减少了某一个网络抖动造成的影响。增加了一个副本之后,还能够解决当主库Crash之后的数据安全性问题,哪怕主库Crash,仍旧有两个副本可以提供服务,不会形成单点。

但是,在引入数据三副本之后,也新引入了一个问题:主库Crash的时候,到底选择哪一个备库作为新的主库?当然,选主的权利仍旧是HA Master来行使,但是HA Master该如何选择?这个问题的简单解决可以使用下面的几个判断标准:

  1. 日志优先。两个Slave,哪个Slave拥有最新的日志,则选择这个Slave作为新的主库。
  2. 主机层面排定优先级。如果两个Slave同时拥有最新的日志,那么该如何选择?此时,选择任何一个都是可以的。例如:可以根据Slave主机IP的大小进行选择,选择IP小的Slave作为新的主库。同样能够解决问题。

新的主库选择出来之后,第一件需要做的事,就是将新的Master和剩余的一个Slave,进行日志的同步,保证二者日志达到一致状态后,对应用提供服务。此时,三副本问题就退化为了两副本问题,三副本带来的防止网络抖动的红利消失,但是由于两副本强同步,数据的可靠性以及一致性仍旧能够得到保障。

当然,除了这一个简单的三副本优化之外,还可以做其他更多的优化。优化的思路一般就是同步转异步处理,例如事务提交写日志操作;使用更细粒度的锁;关键路径可以采用无锁编程等。

多副本强同步,做到极致,并不一定会导致系统的性能损失。极致应该是什么样子的?我的想法是:

  • 对于单个事务来说,RT增加。其响应延时一定会增加(至少多一个网络RT,多一次磁盘Sync);
  • 对整个数据库系统来说,吞吐量不变。远程的网络RT和磁盘Sync并不会消耗本地的CPU资源,本地CPU的开销并未增大。只要是异步化做得好,整个系统的吞吐量,并不会由于引入强同步而降低。
  1. 总结

 

洋洋洒洒写了一堆废话,最后做一个小小的总结:

  • 能够看到这里的朋友,绝逼都是真爱,谢谢你们!!
  • 各种主流关系型数据库系统是否可以实现主备的强一致,是否可以保证不依赖于存储的数据一致性?

        可以。Oracle有,MySQL 5.7,阿里云RDS,网易RDS都有类似的功能。

  • 目前各种关系型数据库系统,能否在保证主备数据强一致的基础上,提供系统的持续可用和高性能?

        可以做,但是难度较大,目前主流关系型数据库缺乏这个能力。

  1. 问题四:一个极端场景的分析

 

意犹未尽,给仍旧在坚持看的朋友预留一个小小的作业。考虑下面这幅图:如果用户的提交操作,在图中的第4步完成前,或者是第4步完成后第5步完成前,主库崩溃。此时,备库有最新的事务提交记录,崩溃的主库,可能有最新的提交记录(第4步完成,第5步前崩溃),也可能没有最新的记录(第4步前崩溃),系统应该如何处理?

8 预留作业

文章在博客上放出来之后,发现大家尤其对这最后一个问题最感兴趣。我选择了一些朋友针对这个问题发表的意见,仅供参考。

@淘宝丁奇

最后那个问题其实本质上跟主备无关。简化一下是,在单库场景下,db本地事务提交完成了,回复ack前crash,或者ack包到达前客户端已经判定超时…所以客户端只要没有收到明确成功或失败,临界事务两种状态都是可以接受的。主备环境下只需要保证系统本身一致。

将丁奇意见用图形化的方式表示出来,就是下面这幅图:

此图,相对于问题四简化了很多,数据库没有主备,只有一个单库。应用发起Commit,在数据库上执行日志落盘操作,但是在返回应用消息时失败(网络原因?超时?)。虽然架构简化了,但是问题大同小异,此时应用并不能判断出本次Commit是成功还是失败,这个状态,需要应用程序的出错处理逻辑处理。

@ArthurHG

最后一个问题,关键是解决服务器端一致性的问题,可以让master从slave同步,也可以让slave回滚,因为客户端没有收到成功消息,所以怎么处理都行。服务器端达成一致后,客户端可以重新提交,为了实现幂等,每个transaction都分配唯一的ID;或者客户端先查询,然后根据结果再决定是否重新提交。

其实,最终的这个问题,更应该由做应用的同学来帮助解答:

如果应用程序在提交Commit操作,但是最后Catch到网络或者是超时的异常时,是怎么处理的?

  1. pi1ot
    3月 27th, 201520:24

    第一个强一致话题,如果slave写入完成,master失败或者crash,client未收到ok结果,又重发起一次更新,岂不是slave就重复操作了?再如果sql不是幂等的,不就出错了?

    • hedengcheng
      3月 27th, 201522:17

      master失败或者是crash,数据库这边一定会完成新的选主,而应用服务器这边,一定是一个请求超时,提交超时。有这些前提,后续应用服务器应该怎么做?

      • allwmh
        3月 28th, 201506:49

        如果说提交超时候 应用进行retry操作的话 会如何呢

        • Ternence
          3月 28th, 201513:02

          感觉和【问题四:一个极端场景的分析】很像啊。我的理解只能通过应用层来处理,因为这个跟DB没有关系了。1、要求事物具有幂等性 2、非幂等性事物通过事物日志记录的方式,防止事物重复提交。
          不知道可不可行 ?

          • hedengcheng
            3月 29th, 201516:15

            这个方案是可行的。

  2. helix
    3月 27th, 201521:42

    好文啊,最后的解决方法是什么?
    限制一个commit完成成功返回,才能继续commit?

  3. detailyang
    3月 27th, 201522:13

    讲解的非常详细,感触很深。

  4. zhaoxin
    3月 27th, 201523:01

    感谢分享。感觉问题4是对问题1中WAL方案的反驳,要实现分布式系统强一致,WAL是不够的,需要一致性协议的应用。

  5. Superwood
    3月 27th, 201523:20

    每次提交都带唯一ID,相同的事务即使两次提交也不会重复执行

  6. hedengcheng
    3月 28th, 201508:47

    微博上,@淘宝丁奇 丁总的回复,对理解最后预留的问题,非常有帮助:@淘宝丁奇: 最后那个问题其实本质上跟主备无关。简化一下是,在单库场景下,db本地事务提交完成了,回复ack前crash,或者ack包到达前客户端已经判定超时…所以客户端只要没有收到明确成功或失败,临界事务两种状态都是可以接受的。主备环境下只需要保证系统本身一致。

    • lili
      3月 28th, 201514:22

      客户端没有接收到成功,然后主备切换,客户端在备机上确能读取到未提交成功的事务,整个主备系统岂不是连顺序一致性都没有满足…..

    • yaoyaminaco
      3月 28th, 201516:42

      我也是这么认为的,不存在主备那么一说,就看成一个双副本+DFS存储的分布式数据库。 客户端提交的transcation失败了,客户端捕捉异常,重新提交即可。重新提交的时候是必然成功的(因为备库被提为主库,原主库crash了)。 后续怎么样追上日志,那是系统本身或者是运维人员需要去干预的事情。

      • hedengcheng
        3月 29th, 201516:12

        赞!就是这个意思。

      • andy
        8月 12th, 201615:31

        按楼主的架构,如果主机没有崩溃,只是客户端超时失败,重新提交的话是会有问题的。其实,分布式的三阶段提交是要求备机写了日志以后,需要等待主机的commited命令,才算是真正事务完成了,不是自己写完了就是成功了的。如果主机没有写日志就崩溃了,事务是不成功的,备机是需要回滚的。

  7. erpeng
    3月 28th, 201511:35

    最后一个问题,可以在应用层面做超时处理。处理逻辑应该是先判断上次操作是否成功,不成功则再次执行。登博,如果HA到master网络有问题,我记得keepalived应该会把master切成slave,为什么会产生双写的问题。

    • hedengcheng
      3月 30th, 201507:51

      keepalived行使的是ha client的功能?这个你确定吗?我们目前集群中自动切换的HA软件,好像都没有配置这个功能。

      • iambowen
        4月 7th, 201511:36

        我们用的是NetScaler,如果HA到Master的访问有问题,那么它会切换到Backup的服务器,也就是另一个数据中心的RDS,两个数据中心之间的是Master-Master关系,不会有双写的问题。

      • erpeng
        4月 9th, 201516:21

        keepalived在主备机器上都会部署。通过虚拟一个ip并且配置指定主备来进行服务,是服务器层面的HA。博文里提的HA应该是数据库的吧。

  8. wptree
    3月 28th, 201511:40

    登博,
    问题二的场景二中原主库主机重启以后,是由该主机上的HAClient来直接将原主库降级还是还需要和HAMaster做一次协商来做降级?

    问题四,只要保证SQL的幂等性就基本没什么问题了;如果不是幂等的,可以做数据唯一性验证;涉及到累加运算的,可能需要特殊处理,commit之前先query一把,这些都是在应用层面做手脚去确保了。

    这套多HAClient-HAMaster高可用机制,目前是各大有技术实力公司在RDBMS上自己做实现呢,还是已经有开源实现呢?

    • hedengcheng
      3月 30th, 201507:55

      最后一个问题,HAClient-HAMaster高可用机制,只是一个事例,目前据我所知,没有人在RDBMS上这样做。

      问题二:这个时候不需要协商的。或者是协商也可以,重启后仍旧发起租约请求,但是由于已经存在新的Master,这一次的协商请求,会收到降级的反馈。

      问题四:谢谢你的建议,这个问题,其实数据库内部是无法搞定的,确实需要应用来配合处理。

      • alex
        4月 1st, 201514:38

        HAClient-HAMaster高可用机制, 腾讯微众银行这边做了。 不过master拆成了了zookeeper+schedule

        • hedengcheng
          4月 2nd, 201515:11

          赞!期待分享。

  9. KryptosX
    3月 28th, 201512:49

    这个流程不应该备库先落盘,应该主库先落盘才对。

  10. Ternence
    3月 28th, 201512:50

    我有一个问题,3副本模式下,二选一日志强同步怎么理解(好像没有特别写这块) :我的理解是如果选择其中一个Slave1,那么每次强同步都应该选择同步到Slave1。否则将会出现Slave1和Slave2数据不一致,并且没法选举出Master的情况。
    是这样吗?

  11. Chenhj
    3月 28th, 201520:34

    有很多疑问。为什么ha作为单独的节点而不是放在db上?白白多了几个节点。还有这个方案为什么没有考虑ha client可能会挂?最后我觉得现有的成熟ha软件结合fence机制是完全可以做到一致性和高可用的,没作者讲得那么悲观.不然你让那些已经上线的ha方案情何以堪。至于性能陨失,不管哪个方案都会有,多少不同而已。

    • hedengcheng
      3月 29th, 201516:14

      可以探讨下,你也可以普及一下,哪一个HA方案可以解决分区可用性的问题?处理的问题也就是文中提到的这些问题。

      • Chenhj
        3月 30th, 201521:30

        分区可用,说白了就是网络故障后该听谁的问题。最简单的办法就是投票看谁拿到多数票。Raft的核心也就是这个吧。我知道至少Pacemaker是可以支持法定投票的,虽然我不知道内部协商的细节,和raft有什么差异,但有了这个投票可靠性就很高,不会发生脑裂了。

        • chuan
          4月 17th, 201516:58

          去除ha集群,仅部署client在db上,会导致ha client处需要存储本集群其它机器的信息,不方便整个集群的管理维护。

  12. 张小贱
    3月 28th, 201523:55

    好文! 有个问题:事务的强一致每次commit都保证落盘,这样性能会比较差,但是如果先把日志写到内存中,一旦主库crash,比如断电,即使有自带电源的内存也只能保证数据不丢失,不能保证主备同步。这种异步的优化和性能该如何抉择。 问题四觉得可以交给应用端去做,如果没有得到明确的成功或失败,就执行一次查询,看看刚才提交的事务是否成功,如果多次都没有结果很可能是连接断掉了。 ~~

  13. kamushin
    3月 29th, 201518:14
    • hedengcheng
      3月 30th, 201507:50

      谢谢提醒,我看下。

  14. xiaosuo
    3月 30th, 201512:07

    最后的不会是2pc吧。

    • hedengcheng
      3月 30th, 201512:53

      这个地方,不需要使用2pc。2pc解决的是分布式事务问题,这里使用2pc,太重了。

  15. zxhdaniel
    3月 31st, 201510:13

    如果应用程序在提交Commit操作,但是最后Catch到网络或者是超时的异常时,是怎么处理的?
    个人觉得,应用层现在也很难处理好这种情况。
    1、回滚。catch到网络超时之后,做一个回滚操作;当然回滚操作是否成功完全没办法保证(可能仍然是网络问题,可能刚好发生主从切换等);然后不管回滚成功与否,都回复操作失败;
    2、重新提交。重新提交或者查询后再提交,因为如果是网络问题,去查询也有可能超时…或者查询成功了,但再次发起操作又超时了…
    怎么处理,可能还得看这个应用是什么场景,如果commit操作本身是人触发的,那可能得做fail-fast的处理,赶紧提示用户操作失败,让用户自己判断操作成功与否再做相应的操作;
    如果是程序触发的commit,那可以直接尝试或者将该事务放到队列里面再离线去处理…

    个人拙见,其实更像是提出问题…期待好的方案出现..

  16. mdkii
    3月 31st, 201520:44

    最后一个问题应该是个普遍问题吧,只要发生跨系统调用就会有此问题发生。当A系统调用B系统服务时,B内部成功了,但是A却不知道。这个时候只能A去重新发起交易了。对于查询,重新发起即可,对于修改动作,要先去确认之前的调用是否成功了。但有没有这种情况:就是A去查询某条记录,B事务成功,但是通知A的时候信息丢失了,此时由于事务成功锁释放了,正好别人把这个记录给修改了,那A这个事务永远不能成功了?

  17. paladin_pan
    4月 1st, 201511:03

    问题二的场景三中的疑问,原文“但是在提升备库之前,原主库所在的HA Client需要做额外的一点事。原主库HA Client发送给HA Master的续租请求,由于网络问题,一直没有得到响应,超过租约时间,主动将本地的主库降级为备库。如此一来,待HA Master将原备库提升为主库时,原来的主库已经被HA Client降级为备库。”,如何保证主库->备库以及备库->主库的切换顺序?还是不需要保证?

    • hedengcheng
      4月 2nd, 201515:11

      需要保证,保证主库降级在备库提升之前。也就是备库提升要比租约时间更大。

      • paladin_pan
        4月 8th, 201510:58

        其实这也是不安全的,timeout机制不是很有效,但是分布式系统很难做到绝对,有一些时候只能相对保证,要看整体系统的诉求

  18. vicehunter
    4月 1st, 201513:53

    在客户端 设置一个seqid,每次submit 成功后加1,当出现错误时,submit 没有+1,重复提交

  19. wcting163
    4月 1st, 201519:13

    mysql.pg.日志都是先写主机,再传备机吧,

    • hedengcheng
      4月 2nd, 201515:13

      我这里是假设数据库如果实现主备强一致,该如何做。MySQL一些版本都支持将binlog落在备库再提交主库的分支。

  20. yeshiquan
    4月 2nd, 201511:36

    博主我有一个问题,“如果租约设定为10秒,那么出各种问题,数据库停服的时间最多为10秒,基本上做到了持续可用”
    如果数据库停服10秒,还叫持续可用吗?这种情况Avaliability不行吧,对线上应用也是灾难的。

    • hedengcheng
      4月 2nd, 201515:17

      任何一种分布式数据库,哪怕是依赖于共享存储的数据库,如Oracle RAC,都不能做到节点宕机后对应用完全的无影响。所谓的持续可用,不是永远处于可用状态,所有的系统都不能达到这个理想状态,而是在一个极短的时间之内从崩溃中恢复可用。

  21. psjay
    4月 10th, 201500:01

    有一点疑问:问题二中,HA Client 挂了怎么办?HA Master 不能和 Client 通信,Client 也不能续租,前者造成 Master 回去尝试提升 Slave 为主,后者造成原来的主不能被顺利降级。

    • hedengcheng
      4月 11th, 201509:09

      不能续租,超过租期后,原主会自动降级

      • psjay
        4月 11th, 201516:14

        降级操作是谁发起的?

        • hedengcheng
          4月 13th, 201520:42

          租约到期内,如果没能续租成功,自动降级。我文章写了。

  22. zhujzhuo
    4月 15th, 201521:35

    openstack trove中就有类似的agent,上报信息给监控端,监控发现主库不可访问会超时重试,重试不成功便会切换贮备关系,飘vip。

  23. zhujzhuo
    4月 15th, 201521:36

    整个架构都是非常棒的,都需要对MySQL 进行二次开发吧

    • hedengcheng
      4月 16th, 201522:37

      今天的数据库大会,腾讯雷海林同学分享的架构,基本上就是按照文章中的架构思路实现了他们不丢数据的MySQL集群。

  24. xgzeng
    4月 18th, 201519:04

    请教。问题二的图提出的架构,有没有单点故障? Master在接收同步确认超时的情况下,应怎么处理?

  25. yifan
    5月 25th, 201520:11

    谈到DB高可用性和强一致性,何老师对于codership的Galera Cluster如何评价?

  26. raolh
    6月 8th, 201517:50

    “所有的这些,在现有数据库的基础上实现,都有着相当的难度。”

    登博,我的ha suite 3.0就是按照这个思路直接在mysql内部做的。一个zookpeer集群作为HA 中心,mysql内部整合了zk的client,并且是做在semisync replication插件里面,保证在同步复制的前提下切主。第一个版本已经做出来了,有机会交流一下。

  27. lxpbs
    7月 1st, 201516:55

    问题四 在当前这种架构下无解 并且会造成应用与数据库数据不一致的严重后果

  28. jacky
    7月 4th, 201514:51

    请教几个问题:
    1. 数据先落slave磁盘与先落master磁盘是否有区别,我个人觉得没啥区别:)
    2. 租约机制能否理解为就是一个双向心跳(ping-pong),节点向ha发送心跳,如果几个心跳周期节点没有收到response则自动降级为slave,同样ha几个心跳周期没有收到心跳则重新选主
    3. 此方案有开源实现么,oceanbase是?

  29. bin
    9月 25th, 201515:01

    估计也就银行会使用强同步数据库系统…

  30. youge
    10月 4th, 201521:29

    文章的基础是架构在主从强一致上,否则数据丢失这个问题难解。赞

  31. zyc
    1月 12th, 201622:16

    为 什么不直接用Raft协议或者Paxos协议进行主备之间的切换和主备之间的同步。Multi-Paxos是非常难以实现的,但是Raft真的实现难度并没有那么巨大。

  32. 刀尖红叶
    1月 22nd, 201614:51

    hedengcheng :
    今天的数据库大会,腾讯雷海林同学分享的架构,基本上就是按照文章中的架构思路实现了他们不丢数据的MySQL集群。

    那阿里RDS有没实现或者准备实现?

  33. wcm
    5月 19th, 201617:03

    在最后,登博快走进死胡同啦。其实好多事情可以换个思路去做。不一定非要用数据库思维去做。丁奇的回答就是个很好的例子。

  34. hhhhh
    7月 14th, 201618:08

    请问一下,2个备库分别为1、2。
    假如假如第一次提交2失败,1成功,主库成功。那是下次提交不同步2了吗?还是要2同步到和1一样的状态,再开始工作