• 从单点到分布式


    本文梳理从单点到分布式遇到的概念及问题,包括:

    • 单点问题
    • 主从
    • 集群
    • 负载均衡
    • 分布式
    • 分布式理论:CAP,BASE
    • 一致性:2PC,3PC,TCC,消息事务,Paxos,Raft

    架构风格:万金油CS与分层中提到了CS架构风格。可以说CS架构风格是分布式架构的起点,所以我们从CS架构风格开始。

    最简单的CS架构就是一个Client+一个Server!Client和Server之间建立连接,然后Server对Client的请求进行响应。

    对于这个最简单的CS架构,有一个很明显的问题:「单点问题」

    即当这唯一的一个Server挂掉以后,Client就无法获得响应了。那怎么解决单点问题呢?非常简单,冗余。

    冗余的方法有两种:主从和集群!

    注意:分布式并不是为了解决单点问题的,而是为了解决单台服务器无法支撑整体业务的问题。

    主从、集群和分布式

    下面举个例子来说明,主从、集群和分布式的区别!

    假设我老婆开了家饭店。因为没钱,早期客户也不是很多,所以就一个人张罗。这就是一个单点。因为如果我老婆有什么事情,那就没法开店了。

    从单点到分布式

    可是我家有两个小孩,老是生病,三天两头的要跑医院,老是关门也不是办法。所以,在老婆有事的时候,我就去开店。我和我老婆就是「主备关系」。

    从单点到分布式

    但是呢,我也要上班,我不可能老是去开店。所以我们都没空的时候,就让我丈母娘帮忙开店。现在我、我老婆和丈母娘之间的关系还是「主备关系」!为什么?因为我们没有同时开店,只是在其他人都有事的时候才来开店的。也就是说同时只有一个服务对外提供服务。

    一段时间后,饭店生意很好。老婆一个人有点忙不过来了。于是我就干脆辞职和老婆一起开店。我们做的事情相同。于是我们就组成了「集群」。我们同时对外提供相同的服务。

    从单点到分布式

    此时如果我老婆有事,那我又变成了一个单点服务。

    再后来,我们两个人也忙不过来了。我们就又招了个服务员。服务员主要工作就是帮忙点菜、收拾碗筷之类的。我们就专心的做饭、收钱。现在我和我老婆之间还是集群,因为我们的工作一样。而我、我老婆和服务员就组成了分布式。我们三个人组成了完整的服务。

    从单点到分布式

    但是呢,现在服务员出现了单点问题。当这个服务员请假的话,我们又忙不过来了。于是我们又招了一个服务员。这两个服务员之间又组成了集群。

    从单点到分布式

    最后,饭店越开越大。我们招了服务员、收银、厨师、洗碗工、清洁员.....组成了一个大的分布式系统。

    从单点到分布式

    而我和我老婆则出去浪去了。

    从单点到分布式

    三者的区别

    从上面的例子,我们可以看出,主从、集群和分布式之间的区别:

    • 主从:同时只有一台服务对外提供服务。当这台服务器挂掉以后,另外一个服务器对外提供服务。
    • 集群:所有服务器同时对外提供服务。有一台或几台服务器挂掉以后,可能有部分客户端会受到影响(看负载均衡算法)
    • 分布式:所有的服务组合成一个完成的系统对外提供服务。如果有一个或多个服务挂掉,那对应的那部分功能就没法使用。每个服务都可以通过集群来确保可用性。

    新的问题

    虽然主从和集群解决了单点的问题。但是从主从到集群、再到分布式,系统间通信成指数级增长,也引入了各种其它问题。

    在单点CS架构下,只有Client和Server之间存在网络通信,Server内部并不存在网络通信。而变成分布式以后,Server间也需要通过网络通信。由于网络的不稳定,可能会出现各种问题。同时由于节点数的增加,Server本身出问题的几率也就提高了,主要可能出现:

    • 通信异常:由于网络的不稳定性,可能导致服务间的通信出现异常
    • 网络分区:由于「通信异常」,可能导致服务间的数据不同步,或者部分服务无法对外服务。就是说,可能客户端访问到的响应有差异。
    • 响应超时:一般来说,正常的调用会返回成功或失败的状态,但是网络通信可能出现超时。超时分为
    • 发送超时:请求并没有到达服务端
    • 响应超时:请求到达了服务端,但是服务端的响应并没有返回到客户端
    • 处理方式:如果请求是幂等的,那可以再次请求。如果不是幂等的,那需要一些补偿措施。
    • 节点故障:服务节点宕机,无法对外提供服务。
    • 节点选择:即Client到哪个节点去获取数据。这就涉及到负载均衡算法,一般的负载均衡算法有(这里不展开)
    • 随机
    • 轮询
    • 加权随机
    • 加权轮询
    • 源地址Hash
    • 一致性Hash

    实际上在分布式系统中,要解决的问题是:「在网络不可靠的情况下,如何保证数据一致性」?

    处理方式有两种:

    • 想办法保证强一致性
    • 不保证强一致性,但保证最终一致性

    强一致性方案

    保证强一致性的思路其实很简单,就是「假设网络在大部分情况下都是正常的,批量的去操作这一批节点,要么全部成功,要么全部失败」!

    操作方式有:

    • 2PC(两阶段提交)
    • 事务补偿TCC(可以说是业务层面的2PC)
    • 3PC(三阶段提交)
    • Sagas:将分布式长事务拆分成多个短事务,由Sagas引擎来协调,具体没有研究。可参考最后的参考资料。

    2PC和3PC都引入了一个「协调者」来协调各个节点(参与者):

    • 客户端提交操作到协调者
    • 协调者与参与者通信,确保各个参与者的操作
    • 如果所有参与者操作成功,协调者返回客户端成功
    • 否则协调者返回客户端失败

    具体流程见下文。

    2PC

    流程:

    • 提交请求阶段(commit-request phase) :
    • 协调者向所有参与者询问是否可以执行提交操作,然后开始等待各参与者的响应
    • 参与者直接就开始执行事务操作,并将Undo信息和Redo信息写入日志
    • 如果参与者的事务操作执行成功,则返回一个「同意」消息;否则返回一个「终止」消息
    • 提交阶段(commit phase) :
    • 当协调者从所有参与者获得的响应消息都为「同意」:
    • 协调者向所有参与者发出「正式提交」的请求
    • 参与者提交事务,并释放事务占用的资源
    • 参与者向协调者发送「完成」消息
    • 协调者收到所有参与者反馈的「完成」消息后,完成事务
    • 如果任一参与者在第一阶段返回「终止」消息,或者协调者在第一阶段超时之前无法获取所有参与者的响应消息:
    • 协调者向所有参与者发出「回滚操作」的请求
    • 参与者利用之前写入的Undo信息执行回滚操作,并释放在整个事务期间占用的资源
    • 参与者向协调者发送「回滚完成」消息
    • 协调者收到所有参与者反馈的「回滚完成」消息后,取消事务

    举例:

    假设两个Server(s1,s2)向三个注册中心节点注册(c1,c2,c3),如果是2PC,流程如下:

    • s1向c1,c2,c3发送「提交请求」,c1,c2,c3接收到了消息,将s1信息保存,并写入Undo和Redo日志,返回「成功」
    • 此时s2向c1,c2,c3发送「提交请求」,但是c1,c2,c3目前被锁定了,所以只能等待
    • s1收到所有的「成功」消息,向c1,c2,c3发送「确认提交」请求,c1,c2,c3提交事务,返回「完成」,s1事务结束
    • s2超时没等到所有的「成功」消息,事务回滚。

    问题:

    二阶段提交的问题很明显:

    • 节点阻塞:在请求阶段,节点就执行了事务操作,并进入阻塞状态。这会导致几个连锁问题:
    • 节点本身阻塞,在这个事务结束之前,这个节点不响应其它请求(上面的例子就是这种情况)
    • 如果节点占用了公共资源,其它想要访问公共资源的第三方节点也会进入阻塞状态
    • 如果在第二阶段出现网络故障,则节点会一直阻塞(可使用超时机制)
    • 数据不一致:在第二阶段提交事务时,可能网络故障了,只有部分节点提交了数据。这就导致了数据不一致。
    • 超时失败:第二阶段,参与者执行完成了,并全部返回完成,但是协调者没有接收到,导致执行了回滚操作
    • 所有参与者都回滚了,事务执行失败(实际事务都执行成功了,但是没有接收到响应)
    • 部分参与者回滚,又导致了数据不一致

    所以2PC并不能保证真正的一致性。

    XA是基于2PC制定的分布式事务规范。JTA是基于XA实现的Java事务接口。

    事务补偿TCC

    TCC将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作:

    • Try:对业务系统做检测及资源预留。类似2PC的阶段一
    • Confirm:对业务系统做确认提交。默认只要Try成功,Confirm一定成功。
    • Cancel:在业务执行错误时,执行的业务取消,释放预留资源

    举例:

    还是假设两个Server(s1,s2)向三个注册中心节点注册(c1,c2,c3),如果是TCC,流程如下:

    • s1向c1,c2,c3发送「Try请求」,c1,c2,c3接收到了消息,锁定服务列表信息,返回「成功」
    • 此时s2向c1,c2,c3发送「Try请求」,锁定失败,可以等待或重试
    • s1收到所有的「成功」消息,向c1,c2,c3发送「Confirm提交」请求,c1,c2,c3提交事务,返回「完成」,s1事务结束

    问题:

    TCC的主要问题是适用性问题,因为是业务层的事务管理,所以需要针对具体的业务进行具体的Try/Confirm/Cancel的实现。

    3PC

    为了解决2PC的阻塞问题,就有了三阶段提交。三阶段提交将二阶段提交的「请求阶段」拆分为「CanCommit阶段」和「PreCommit阶段」。具体流程如下:

    • CanCommit阶段: 协调者向参与者发送提交请求,参与者如果可以提交就返回「是」,否则返回「否」。(注意,这里并不会执行事务,所以也不会阻塞)
    • PreCommit阶段:
    • 如果参与者都返回「是」,则进行事务的预执行:
    • 协调者向参与者发送PreCommit请求,并进入Prepared阶段
    • 参与者接收到PreCommit请求后,执行事务操作,并将undo和redo信息记录到事务日志中
    • 如果参与者执行成功,则返回「完成」消息,并等待最终指令
    • 假如有任何一个参与者向协调者发送了「否」,或者等待超时,那么就中断事务:
    • 协调者向所有参与者发送终止请求
    • 参与者收到终止请求后(或超时仍未收到协调者的请求),则终止事务
    • DoCommit阶段:该阶段提交事务,也分为两种情况:
    • 如果协调者接收到所有参与者返回的「完成」,则从PreCommit状态进入DoCommit状态,同时向所有参与者发送doCommit请求
    • 参与者接收到doCommit请求之后,提交事务,并在完成之后释放所有的资源
    • 事务提交完之后,向协调者发送「提交完成」响应
    • 协调者接收到所有参与者的「提交完成」响应之后,完成事务
    • 如果协调者没有接收到所有参与者发送的「提交完成」响应(参与者返回的不是「提交完成」响应或者超时没有返回任何信息),则终止事务

    举例:

    依然假设两个Server(s1,s2)向三个注册中心节点注册(c1,c2,c3),如果是3PC,流程如下:

    • s1向c1,c2,c3发送「CanCommit请求」,c1,c2,c3接收到了消息,返回「OK」
    • 此时s2向c1,c2,c3发送「CanCommit请求」,c1,c2,c3接收到了消息,也返回「OK」
    • s1收到所有的「成功」消息,向c1,c2,c3发送「PreCommit请求」,c1,c2,c3将s1信息保存,并写入Undo和Redo日志,返回「成功」
    • s2收到所有的「成功」消息,向c1,c2,c3发送「PreCommit请求」,c1,c2,c3返回「失败」
    • s1收到所有的「成功」消息,向c1,c2,c3发送「DoCommit请求」,c1,c2,c3提交事务,释放资源,返回成功。事务完成
    • s2收到「失败」消息,事务回滚

    问题:

    3PC同样会出现数据不一致的情况,在第三阶段协调者终止事务,但是参与者没有接收到,则可能导致数据不一致。

    最终一致性

    可以看到,强一致性在任何一个节点出现问题后,事务都会失败。在事务要求不是很高的情况下,并不一定要保证强一致性,只要保证最终一致性就可以了。保证最终一致性的思路是基于CAP定理和BASE理论。

    CAP定理

    《JDBC的架构设计》中提到了本地事务的ACID特性:

    • 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行
    • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束
    • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行
    • 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中

    CAP里也有一个A和一个C。但是实际两者之间并没有什么关系。CAP中的C、A、P分别是:

    • 一致性(Consistency):这里的一致性指的是数据在多个副本之间保持强一致
    • 可用性(Availability):指系统可以对外提供服务,这是一个架构属性。关于架构属性可参考之前的文章《什么是架构属性》
    • 分区容错性(Partition tolerance):这里的分区指的是「网络分区」。指的是除非整个网络环境都发生了故障,否则系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务

    CAP定理,说的是「对于一个分布式系统来说,不可能同时满足一致性、可用性和分区容错性。最多只能满足其中两项」!

    那我们应该满足哪两项呢?这个都知道了,就是「分区容错性」和「可用性」,同时保证「最终一致性」!那为什么呢?

    我们来假设:

    • 假如放弃可用性:即系统遇到任何问题,就对外不可用。上面说了,分布式系统网络间通信数量大大增加,如果网络一波动,系统就不可用。那实际可用性还不如单点应用。那还要搞分布式干嘛?
    • 假如放弃分区容错性:避免网络分区的方法就是将数据集中管理,又变成了单点应用了。
    • 假如放弃强一致性:强一致性指的是像数据库事务那样,操作完了以后,所有的数据都是一致的。但是在分布式系统里面,如果出现了网络分区或者网络延时,那么是无法保证强一致性的。虽然放弃了强一致性,但是可以使用各种手段来保证最终一致性。就是说当网络故障恢复后,或者网络通信结束后,保证各个副本的数据一致。

    BASE理论

    BASE理论是CAP的实践理论。其核心思想是:「根据CAP定理,我们知道系统是无法做到强一致性的,但系统可以根据自身的业务特点,采用适当的方式来使系统达到最终一致。」

    BASE包括:

    • 基本可用(Basically Available):在系统出现故障时,相对于正常的系统来说,可能有某些服务降级,但是还是能正常对外提供服务。服务降级包括:
    • 响应时间:即比正常系统响应时间慢
    • 功能:某些功能可能不可用。比如18年双11,淘宝的地址服务就挂了,但是不影响用户败家,只是不能修改地址而已。
    • 软状态(Soft State):指系统在最终一致之前的中间状态(即数据在一部分节点中,但还没有同步到所有的节点),该状态不影响系统的整体可用性。
    • 最终一致性(Eventually Consistent):系统从软状态中,经过一段时间,最终需要达到数据一致。这个「时间」取决于网络延时、系统负载、数据复制方案等因素。

    可以看出,现在的主要问题就是「如何保证最终一致性」?

    最终一致性方案

    保证最终一致性的方法有:

    • 消息事务
    • Paxos算法
    • Raft

    消息事务

    消息事务的原理很简单,通过消息队列来保障最终一致性,大致流程为:

    • 在提交事务时,需要提交一份数据到消息队列。两者要么全部成功,要么全部失败
    • 消息队列消费端消费消息,执行后续的任务
    • 如果执行成功则结束
    • 如果因为网络原因执行失败,则重试。如果因为业务原因执行失败,则可以写入一个补偿消息。消息生产方进行数据回滚

    举例:

    还是假设Server(s1,s2)向三个注册中心节点注册(c1,c2,c3),消息事务流程如下:

    • s1向c1和消息队列提交注册信息,提交成功
    • s2向c1和消息队列提交注册信息,提交成功
    • c2,c3监听到消息队列的消息,依次执行注册信息
    • 执行成功则c1,c2,c3的服务列表最终都是一致的
    • 如果c2执行s2失败,则需要向消息队列发送一个撤销操作,c1,c2接收到消息后,撤销s2的信息,s2接收到消息后,事务失败。

    Paxos算法

    普遍认为Paxos比较难理解,即使Lamport不使用任何公式写的《Paxos Made Simple》论文也都比较难以理解。

    我觉得《Paxos Made Simple》难以理解的原因有两个:

    • 论文中没有明确「提案」和「Value」之间的关系,前面说「Value」,后面又说「提案」。实际上「提案」包括了「提案编号」和「提案值」(也就是Value),提案编号是一个全序ID,即全局唯一且是递增的。
    • 论文里面描述的Paxos算法分为两个阶段,但是这里的两个阶段和2PC里所说的两阶段意义是不同的。2PC中的两个阶段是它的完整流程就是两个阶段,而Paxos里的两个阶段是交替执行的,直到达到最终一致。也就是说,对一次Paxos计算来说,可能要经过多次的阶段一、阶段二,才会达到最终一致

    论文中对Paxos算法的流程描述如下:

    阶段一:

    • Proposer选择一个提案号n,向大部分的Acceptor发送携带了提案号n的prepare请求
    • 如果Acceptor接收到了prepare请求,请求携带的提案号n大于它所响应的prepare请求所携带的提案号,那么它会返回一个响应,这个响应包含了它所通过的最大编号的提案(如果存在的话)
    • ,并保证以后都不会再接收提案号小于n的请求了
    • 阶段二:
    • 如果Proposer接收到了大部分Acceptor的响应,然后Proposer就发送accept请求给Acceptor,这个accept请求包含了提案号n和值v,这个v是前面Acceptor返回的最大编号的提案里的值,如果Acceptor没有返回任何提案,则v由Proposer自定义
    • 如果Acceptor接收到了提案号为n的accept请求,如果它没有响应任何提案号大于n的prepare请求,它就接收这个提案
    Paxos中有三个角色Proposer提出提案,Acceptor接收提案,Learner获取提案

    它主要保证了,在一次提案提交过程中(也就是一个Paxos计算中):

    • 只有提案被提交了,那么它里面的值才能被选中
    • 最终只能有一个值被选中
    • 如果某个进程获取到了某个值,那么这个值一定是被选中的那个值

    举例

    下面我还是以注册中心的流程,来阐述BasicPaxos算法(MultiPaxos这里不讨论)!

    在这里Server可以说是Proposer,注册中心则是Acceptor,Client则是Learner。

    假设有三个Server,P1[192.168.1.1],P2[192.168.1.2],P3[192.168.1.3]。五个注册中心节点A1,A2,A3,A4,A5。三个客户端L1,L2,L3。现在P1,P2都是第一次注册到注册中心(第一次计算):

    • P1,P2从全局ID生成器那里分别获取一个提案编号,P1[100],P2[101]
    • P1携带提案编号100向A1,A3,A5发送prepare请求。但是因为网络不太好,A1,A3成功接收,但是A5发送失败了。A1,A3接收到了提案,记录下提案编号100,并保证以后不会再同意编号小于100的提案。因为是第一次接收提案,所以A1,A3都没有值返回。
    • P2携带提案编号101向A1,A2,A5发送prepare请求。都发送成功了。A2,A5是第一次接收到提案,所以直接记录下提案编号101,并保证以后不会再同意编号小于101的提案。因为是第一次接收提案,所以A2,A5都没有值返回。对于A1来说,因为已经接收到P1的提案,但是101大于100,所以记录下101,并保证以后不会再同意编号小于101的提案。虽然A1接收了P1的prepare请求,但是并没有接收到任何值,所以也没有返回。
    • P1接收到了A1,A3的响应,但是没有满足大多数。所以它重新获取了一个提案编号120,准备重新发送。
    • 在此之前,P2接收到了A1,A2,A5的响应,将自己的IP作为值,并携带编号101一起[101,[192.168.1.2]],向A1,A2,A5发送accept请求。A1,A2,A5都接收了这个提案,并记录了下来。
    • P1重新向A1,A3,A5发送prepare请求[120]。因为120大于A1,A3,A5所记录的提案号,所以A1,A3,A5都记录下来这个提案编号。由于A1,A5已经记录了P2的值,所以返回P2的值给P1。A3没有返回。
    • P1接收到了A1,A3,A5的响应,开始发送accept请求,但是A1,A5返回了P2的值,所以P1只能发送[120,[192.168.1.2]]到A1,A3,A5。
    • 第一次计算结束,目前A1,A3,A5记录的是[120,[192.168.1.2]]。A2记录的是[101,[192.168.1.2]],虽然编号不一样,但是值是一样的。A4则可以通过学习得到最终的服务列表。

    但是P1明显没有注册上去,所以它又开始了第二次注册尝试(第二次Paxos计算),这时呢,P3也开始注册了:

    • P1,P3从全局ID生成器那里分别获取一个提案编号,P1[210],P3[211]
    • P1携带提案编号210向A1,A3,A5发送prepare请求。A1,A3,A5接收到了提案,记录下提案编号210,并保证以后不会再同意编号小于210的提案。因为这里是新的一次Paxos计算,所以这里实际还是第一次接收数据,所以不会返回提案值。
    • P3携带提案编号211向A2,A4,A5发送prepare请求。因为211大于210,所以A2,A4,A5接收到了提案,记录下提案编号211,并保证以后不会再同意编号小于211的提案。这里也不会返回提案值。
    • P1接收到了响应,开始发送access请求[210,[192.168.1.1]]到A1,A3,A5。A1,A3接收了这个提案,但是A5的提案号现在是211,它不接收这个提案。
    • P3接收到了响应,开始发送access请求[211,[192.168.1.3]]到A2,A4,A5。A2,A4,A5接收了这个提案。
    • P1重新获取了新的ID220,再次向A1,A3,A5发送prepare请求,A1,A3,A5都同意了。A1,A3返回[210,[192.168.1.1]],A5返回[211,[192.168.1.3]]
    • P1接收到响应,只能发送[220,[192.168.1.3]]的prepare请求到A1,A3,A5。A1,A3,A5全部同意。
    • 至此第二次计算结束,目前A1,A3,A5记录的是[220,[192.168.1.3]]。P3,A2,A4记录的是[211,[192.168.1.3]],虽然编号不一样,但是值是一样的。P2则通过学习可以得到最终的服务列表。

    现在P1还是没注册上去,所以再来第三次注册尝试(第二次Paxos计算),现在就它一个注册了:

    • P1从全局ID生成器那里获取一个提案编号P1[310]
    • P1携带提案编号310向A1,A3,A5发送prepare请求。A1,A3,A5接收到了提案,记录下提案编号310,并保证以后不会再同意编号小于310的提案。因为这里是新的一次Paxos计算,所以这里实际还是第一次接收数据,所以不会返回提案值。
    • P1接收到了响应,开始发送access请求[310,[192.168.1.1]]到A1,A3,A5。A1,A3,A5接收了这个提案。
    • 其它节点可以通过学习,获得最终的服务列表。

    Raft

    Raft中也有三个角色:

    • Leader(领袖):处理客户端交互,一般一次只有一个Leader(如果出现网络分区,可能会出现多个Leader,但不影响最终一致性)
    • Follower(群众):默认情况下都是Follower,Leader从Follower中选举出来
    • Candidate(候选人):将要被选为Leader的Follower

    Raft也分为两个阶段:

    • 选举阶段
    • 由选举出来的Learder负责和客户端交互,同步各个Follower

    整个过程和美国大选类似:

    • 选举阶段(选总统)
    • Follower在随机等待一段时间后,转换为Candidate,立即先给自己投一票,然后向其它的Follower拉票,Follower进行投票,投票多的那个就是Leader
    • 如果出现了两个Candidate票数相同的,那么就再等待一段时间,由这两个Candidate再次拉票,票数多的就是Leader
    • 选出来的Leader通过心跳机制和Follower确立leader地位。如果Leader挂了,则重新选出新的Leader(这个Leader的数据必须是最新的)
    • Leader阶段(总统处理国事,并公告)
    • Leader接收到Client的消息后,此时为Uncommitted状态
    • Leader向所有的Follower复制这个消息,并等待Follower的响应
    • 当大多数的Follower返回后,Leader返回Client成功响应。此时为Committed状态
    • Leader告知Follower,该数据已提交

    举例:

    还是假设Server(s1,s2)向三个注册中心节点注册(c1,c2,c3),Raft流程如下:

    • c1,c2,c3先选举出一个Leader,假设c1胜出
    • c1和c2,c3建立心跳,并等待Server注册
    • s1发送注册信息,c1接收,然后复制给c2和c3
    • s2发送注册信息,c1接收,然后复制给c2和c3。这里相当于已经退化成了单CS架构了
    • c1接收到c2,c3成功接收s1消息的响应,告知s1,事务成功
    • 但是c2接收s2消息失败,此时可以尝试重试,或者回滚事务

    一致性方案选择

    「强一致性」较「最终一致性」可靠性和性能都较差(Paxos由于逻辑复杂性能也不行),但是实现简单,「最终一致性」则反之。方案的选择,视具体情况而定:

    • 对于需要强一致性的业务来说,则放弃部分性能,使用强一致性。比如转账业务
    • 对于性能要求高,但是数据一致性要求并不是太强的业务,可以使用最终一致性。比如大V发微博

    参考资料

    • 《PaxosMadeSimple》http://lamport.azurewebsites.net/pubs/pubs.html#paxos-simple
    • 《Base: An Acid Alternative》https://queue.acm.org/detail.cfm?id=1394128
    • Wiki二阶段提交https://zh.wikipedia.org/wiki/%E4%BA%8C%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4
    • Wiki三阶段提交https://zh.wikipedia.org/wiki/%E4%B8%89%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4
    • Wiki XAhttps://zh.wikipedia.org/wiki/X/Open_XA
    • Sagashttps://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf
    • CONSENSUS: BRIDGING THEORY AND PRACTICEhttps://ramcloud.stanford.edu/~ongaro/thesis.pdf

  • 相关阅读:
    iOS 微信分享提示 未验证应用
    iOS 升级xcode12后原项目模拟器运行报错
    ZK进程监控
    kakafka
    mysql 通过使用联全索引优化Group by查询
    4. php反序列化从入门到放弃(放弃篇)
    微慕小程序专业版V3.5发布-小商店
    C++ Singleton模式
    C语言的clone与mmap调用
    InnoDB MVCC机制
  • 原文地址:https://www.cnblogs.com/ivaneye/p/14057447.html
Copyright © 2020-2023  润新知