共计 3709 个字符,预计需要花费 10 分钟才能阅读完成。
在分布式系统中著有 CAP 实践,该实践由加州大学伯克利分校的 Eric Brewer 传授提出,论述了在一个分布式系统中不可能同时满足 一致性(Consistency)、可用性(Availability),以及 分区容错性(Partition tolerance)。
- C:一致性
在分布式系统中数据往往存在多个正本,一致性形容的是这些正本中的数据在内容和组织上的统一。
- A:可用性
可用性形容了系统对用户的服务能力,所谓可用是指在用户容忍的工夫范畴内返回用户冀望的后果。
- P:分区容错性
分布式系统通常由多个节点形成,因为网络是不牢靠的,所以存在分布式集群中的节点因为网络通信故障导致被孤立成一个个小集群的可能性,即网络分区,分区容错性要求在呈现网络分区时零碎依然可能对外提供一致性的可用服务。
对于一个分布式系统而言,咱们要始终假如网络是不牢靠的,因而分区容错性是对一个分布式系统最根本的要求,咱们的切入点更多的是尝试在可用性和一致性之间寻找一个平衡点,但这也并非要求咱们在零碎设计时始终建设在网络呈现分区的场景之上,而后对一致性和可用性在抉择时非此即彼。实际上 Eric Brewer 在 2012 年就曾指出 CAP 实践证实不能同时满足一致性、可用性,以及分区容错性的观点在理论零碎设计领导上存在肯定的误导性。传统对于 CAP 实践的了解认为在设计分布式系统时必须满足 P,而后在 C 和 A 之间进行取舍,这是全面的,理论中网络呈现分区的可能性还是比拟小的,尤其是目前网络环境正在变得越来越好,甚至许多零碎都领有专线反对,所以在网络未呈现分区时,还是应该兼顾 A 和 C;另外就是对于一致性、可用性,以及分区容错性三者在度量上也应该有一个评定范畴,最简略的以可用性来说,当有多少占比申请呈现响应超时才能够被认为是不满足可用性,而不是一呈现超时就认为是不可用的;最初咱们须要思考的一点就是分布式系统个别都是一个比拟大且简单的零碎,咱们应该从更小的粒度上对各个子系统进行评估和设计,而不是简略的从整体上认为须要满足 P,而在 A 和 C 之间做取舍,一些子系统可能须要尽可能同时满足三者。
让分布式集群始终对外提供可用的一致性服务始终是富裕挑战和趣味的一项工作。暂且抛开可用性,拿一致性来说,对于关系型数据库咱们通常利用事务来保证数据的强一致性,当咱们的数据量越来越大,大到单库曾经无奈承当时,咱们不得不采取分库分表的策略对数据库实现程度拆分,构建分布式数据库集群,这样能够将一个数据库的压力摊派到多个数据库,极大的晋升了数据库的存储和响应能力,然而拆分之后也为咱们应用数据库带来了许多的限度,比方主键的全局惟一、联表查问、数据聚合等等,另外一个相当辣手的问题就是数据库的事务由原先的单库事务变成了当初的分布式事务。
分布式事务的实现并不是很难,比方下文要开展的两阶段提交(2PC:Two-Phrase Commit)和三阶段提交(3PC:Three-Phrase Commit)都给咱们提供了思路,然而如果要保证数据的强一致性,并要求对外提供可用的服务,就变成了一个简直不可能的工作(至多目前是),因而很多分布式系统对于数据强一致性都敬而远之。
两阶段提交协定(2PC:Two-Phrase Commit)
两阶段提交协定的指标在于在分布式系统中保证数据的一致性,许多分布式系统采纳该协定提供对分布式事务的反对(提供但不肯定有人用,呵呵~)。顾名思义,该协定将一个分布式的事务过程拆分成两个阶段:投票阶段和事务提交阶段。为了让整个数据库集群可能失常的运行,该协定指定了一个“协调者”单点,用于协调整个数据库集群的运行,为了简化形容,咱们将数据库外面的各个节点称为“参与者”,三阶段提交协定中同样蕴含“协调者”和“参与者”这两个定义。
第一阶段:投票阶段
该阶段的次要目标在于打探数据库集群中的各个参与者是否可能失常的执行事务,具体步骤如下:
- 协调者向所有的参与者发送事务执行申请,并期待参与者反馈事务执行后果。
- 事务参与者收到申请之后,执行事务,但不提交,并记录事务日志。
- 参与者将本人事务执行状况反馈给协调者,同时阻塞期待协调者的后续指令。
第二阶段:事务提交阶段
在第一阶段协调者的询盘之后,各个参与者会回复本人事务的执行状况,这时候存在三种可能:
- 所有的参与者回复可能失常执行事务
- 一个或多个参与者回复事务执行失败
- 协调者期待超时。
对于第一种状况,协调者将向所有的参与者收回提交事务的告诉,具体步骤如下:
- 协调者向各个参与者发送 commit 告诉,申请提交事务。
- 参与者收到事务提交告诉之后,执行 commit 操作,而后开释占有的资源。
- 参与者向协调者返回事务 commit 后果信息。
对于第二、三种状况,协调者均认为参与者无奈失常胜利执行事务,为了整个集群数据的一致性,所以要向各个参与者发送事务回滚告诉,具体步骤如下:
- 协调者向各个参与者发送事务 rollback 告诉,申请回滚事务。
- 参与者收到事务回滚告诉之后,执行 rollback 操作,而后开释占有的资源。
- 参与者向协调者返回事务 rollback 后果信息。
两阶段提交协定解决的是分布式数据库数据强一致性问题,其原理简略,易于实现,然而毛病也是不言而喻的,次要毛病如下:
- 单点问题
协调者在整个两阶段提交过程中扮演着无足轻重的作用,一旦协调者所在服务器宕机,那么就会影响整个数据库集群的失常运行,比方在第二阶段中,如果协调者因为故障不能失常发送事务提交或回滚告诉,那么参与者们将始终处于阻塞状态,整个数据库集群将无奈提供服务。
- 同步阻塞
两阶段提交执行过程中,所有的参与者都须要服从协调者的对立调度,期间处于阻塞状态而不能从事其余操作,这样效率及其低下。
- 数据不一致性
两阶段提交协定尽管为分布式数据强一致性所设计,但依然存在数据不一致性的可能,比方在第二阶段中,假如协调者收回了事务 commit 的告诉,然而因为网络问题该告诉仅被一部分参与者所收到并执行了 commit 操作,其余的参与者则因为没有收到告诉始终处于阻塞状态,这时候就产生了数据的不一致性。
三阶段提交协定(2PC:Three-Phrase Commit)
针对两阶段提交存在的问题,三阶段提交协定通过引入一个“预询盘”阶段,以及超时策略来缩小整个集群的阻塞工夫,晋升零碎性能。三阶段提交的三个阶段别离为:can_commit,pre_commit,do_commit。
第一阶段:can_commit
该阶段协调者会去询问各个参与者是否可能失常执行事务,参与者依据本身状况回复一个预估值,绝对于真正的执行事务,这个过程是轻量的,具体步骤如下:
- 协调者向各个参与者发送事务询问告诉,询问是否能够执行事务操作,并期待回复
- 各个参与者根据本身情况回复一个预估值,如果预估本人可能失常执行事务就返回确定信息,并进入准备状态,否则返回否定信息
第二阶段:pre_commit
本阶段协调者会依据第一阶段的询盘后果采取相应操作,询盘后果次要有三种:
- 所有的参与者都返回确定信息
- 一个或多个参与者返回否定信息
- 协调者期待超时
针对第一种状况,协调者会向所有参与者发送事务执行申请,具体步骤如下:
- 协调者向所有的事务参与者发送事务执行告诉
- 参与者收到告诉后,执行事务,但不提交
- 参与者将事务执行状况返回给客户端
在下面的步骤中,如果参与者期待超时,则会中断事务。 针对第二、三种状况,协调者认为事务无奈失常执行,于是向各个参与者收回 abort 告诉,申请退出准备状态,具体步骤如下:
- 协调者向所有事务参与者发送 abort 告诉
- 参与者收到告诉后,中断事务
第三阶段:do_commit
如果第二阶段事务未中断,那么本阶段协调者将会根据事务执行返回的后果来决定提交或回滚事务,分为三种状况:
- 所有的参与者都能失常执行事务
- 一个或多个参与者执行事务失败
- 协调者期待超时
针对第一种状况,协调者向各个参与者发动事务提交申请,具体步骤如下:
- 协调者向所有参与者发送事务 commit 告诉
- 所有参与者在收到告诉之后执行 commit 操作,并开释占有的资源
- 参与者向协调者反馈事务提交后果
针对第二、三种状况,协调者认为事务无奈失常执行,于是向各个参与者发送事务回滚申请,具体步骤如下:
- 协调者向所有参与者发送事务 rollback 告诉
- 所有参与者在收到告诉之后执行 rollback 操作,并开释占有的资源
- 参与者向协调者反馈事务提交后果
在本阶段如果因为协调者或网络问题,导致参与者迟迟不能收到来自协调者的 commit 或 rollback 申请,那么参与者将不会如两阶段提交中那样陷入阻塞,而是期待超时后持续 commit。绝对于两阶段提交尽管升高了同步阻塞,但依然无奈防止数据的不一致性。
在分布式数据库中,如果冀望达到数据的强一致性,那么服务根本没有可用性可言,这也是为什么许多分布式数据库提供了跨库事务,但也只是个陈设的起因,在理论利用中咱们更多谋求的是数据的弱一致性或最终一致性,为了强一致性而抛弃可用性是不可取的。
起源:https://my.oschina.net/wangzh…
欢送关注公众号【码农开花】一起学习成长
我会始终分享 Java 干货,也会分享收费的学习材料课程和面试宝典
回复:【计算机】【设计模式】【面试】有惊喜哦