从单点到分布式

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

  • 单点问题
  • 主从
  • 集群
  • 负载均衡
  • 分布式
  • 分布式理论: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

posted @ 2020-11-29 19:20  一瑜一琂  阅读(916)  评论(1编辑  收藏  举报