这是我参与「第五届青训营 」伴学笔记创作活动的第10天
一、分布式架构介绍
(一)什么是分布式系统
分布式系统指一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。
通俗的理解,分布式系统就是一个业务拆分成多个子业务,分布在不同的服务器节点,共同构成的系统称为分布式系统,同一个分布式系统中的服务器节点在空间部署上是可以随意分布的,这些服务器可能放在不同的机柜中,也可能在不同的机房中,甚至分布在不同的城市。
(二)分布式与集群的区别
集群指多个服务器做同一个事件
分布式指多个服务器做不同事情
(三)分布式系统特性
- 分布性
空间中随机分布。这些计算机可以分布在不同机房,不同城市,甚至不同的国家
- 对等性
分布式系统中的计算机没有主从之分,组成分布式系统的所有节点都是对等的;
- 并发性
同一个分布式系统的多个节点,可能会并发地操作一些共享资源,诸如数据库或分布式存储;
- 缺乏全局时钟性
各个计算机之间是依赖于交互信息来进行相互通信,很难定义两件事情的先后顺序,缺乏全局始终控制序列;
- 故障总会发生
组成分布式的计算机,都有可能在某一时刻突然间崩掉。分的计算机越多,可能崩掉一个的机率就越大。如果再考虑到设计程序的异常故障,也会加大故障的概率。
- 处理单点故障
单点SPoF(Single Point Of Failure):某个角色或功能只有某一台计算机在支撑,在这台计算机上出现的故障是单点故障;
(四)分布式系统面临问题
- 通信异常
网络本身的不可靠性,因此每次网络通信都会伴随着网络不可用的风险(光纤、路由、DNS等硬件设备或系统的不可用),都会导致最终分布式系统无法顺利进行一次网络通信,另外,即使分布式系统各节点之间的网络通信能够正常运行,其延时也会大于单机操作,存在巨大的延时差别,也会影响消息的收发过程,因此消息丢失和 消息延迟变的非常普遍;
- 网络分布
网络之间出现了网络不连通,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成若干个孤立的区域,分布式系统就会出现局部小集群,在极端情况下,这些小集群会独立完成原本要整个分布式系统才能完成的功能,包括数据的事务处理,这就对分布式一致性提出非常大的挑战;
- 节点故障
节点故障是分布式系统下另一个比较常见的问题,指的是组成分布式系统的服务器节点出现的宕机或“僵死”现象,根据经验来说,每个节点都有可能出现故障,并且经常发生;
- 三态
分布式系统每一次请求与响应存在特有“三态”概念,即成功、失败和超时;
- 重发
分布式系统在发生调用的时候可能会出现失败、超时的情况,这个时候需要重新发起调用
- 幂等
一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
二、分布式理论
分布式数据一致性,指的是数据在多份副本中存储时,各副本中的数据是一致的;
分布式系统当中,数据往往会有多个副本。多个副本就需要保证数据的一致性。这就带来了同步的问题,因为网络延迟问题等因素,我们几乎没有办法保证可以同时更新所有机器当中的包括备份所有数据,就会有数据不一致的情况。
一致性分为:
- 强一致性
系统在写入成功后,会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。
- 弱一致性
系统在写入成功后,会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。
- 最终一致性
最终一致性也是弱一致性的一种,它无法保证数据更新后,所有后续的访问都能看到最新数值,而是需要一个时间,在这个时间之后可以保证这一点(就是一段时间后,节点间的数据会最终达到一致状态),而在这个时间内,数据也许是不一致的,这个系统无法保证强一致性的时间片段被称为“不一致窗口”。不一致窗口的时间长短取决于很多因素,比如备份数据的个数、网络传输延迟速度、系统负载等。
最终一致性在实际应用中又有多种变种:
- 因果一致性
如果进程A通知进程B它已更新了一个数据项,那么进程B的后续访问将返回更新后的值。与进程A无因果关系的进程C的访问遵守一般的最终一致性规则
- 读己之所写一致性
当进程A自己更新一个数据项之后,它总是访问到更新过的值,绝不会看到旧值。这是因果一致性模型的一个特例
- 会话一致性
它把访问存储系统的进程放到会话的上下文中。只要会话还存在,系统就保证“读己之所写”一致性。如果由于某些失败情形令会话终止,就要建立新的会话,而且系统保证不会延续到新的会话。
- 单调读一致性
如果一个进程已经读取到特定值,那么该进程不会读取到该值以前的任何值
- 单调写一致性
系统保证对同一个进程的写操作串行化
(二)CAP定理
CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
一致性:所有节点访问时都是同一份最新的数据副本
可用性:每次请求都能获取到不错的响应,但是不保证获取的数据为最新数据
分区容错性:分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障
因此,我们只能二选一:
CA(Consistency+Availability):关注一致性和可用性,它需要非常严格的全体一致的协议;
CP(Consistency+partition tolerance):关注一致性和分区容忍性。它关注的是系统里大多数人的一致性协议。这样的系统只需要保证大多数结点数据一致,而少数的结点会在没有同步到最新版本的数据时变成不可用的状态。这样能够提供一部分的可用性。
AP(availability + partition tolerance):这样的系统关心可用性和分区容忍性。因此,这样的系统不能达成一致性,需要给出数据冲突,给出数据冲突就需要维护数据版本。
放弃一致性,满足分区容错,那么节点之间就有可能失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会容易导致全局数据不一致性。对于互联网应用来说,机器数量庞大,节点分散,网络故障正常不过了,那么此时就是保障AP,放弃C的场景,而从实际中理解,像网站这种偶尔没有一致性是能接受的,但不能访问问题就大了。
对于银行来说,就是必须保证强一致性,也就是说C必须存在,那么就只有CA和CP两种情况,当保障一致性和可用性(CA),那么一旦出现通信故障,系统将完全不可用。另一方面,如果保障了强一致性和分区容错(CP),那么就具备了部分可用性。实际应该选择什么,是需要通过业务场景进行权衡的(并不是所有情况都是CP好于CA,只能查看信息但不能更新信息有时候还不如直接拒绝服务)
(三)BASE理论
BASE:全称 Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写,BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大型互联网分布式实践的总结,是基于CAP定理逐步演化而来的。其核心思想是:既是无法做到强一致性,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。
1、Basically Available(基本可用)
假设系统,出现 了不可预知的故障,但还是能用,相比较正常的系统而言:
- 响应时间上的损失:正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在1秒返回结果;
- 功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单,但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面;
2、Soft state(软状态)
相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种“硬状态”。
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不会影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
3、Eventually consistent(最终一致性)
上面说的软状态,不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性。从而达到数据的最终一致性。这个时间期限取决于网络延时,系统负载,数据复制方案设计等等因素。
Base 理论是在 CAP 上发展的,CAP 理论描述了分布式系统中数据一致性、可用性、分区容错性之间的制约关系,当你选择了其中的两个时,就不得不对剩下的一个做一定程度的牺牲。
Base 理论则是对 CAP 理论的实际应用,也就是在分区和副本存在的前提下,通过一定的系统设计方案,放弃强一致性,实现基本可用,这是大部分分布式系统的选择,比如 NoSQL 系统、微服务架构。
三、分布式一致性协议
(一)两阶段提交协议(2PC)
两阶段提交协议,简称2PC(2 Prepare Commit)是比较常用的解决分布式事务问题的方式,要么所有参与进程都提交事务,要么都取消事务,即实现ACID中的原子性的常用手段。
分布式事务:事务提供一种操作本地数据库的不可分割的一系列操作“要么什么都不做,要么做全套”的机制,而分布式事务就是为了操作不同数据库的不可分割的一系列操作“要么什么都不做,要么做全套”的机制;
1、成功执行事务提交流程
阶段一:
- 事务询问
协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应;
- 执行事务
- 各参与者向协调者反馈事务询问的响应
阶段二:
- 发送提交请求
协调者向所有参与者发出commit请求;
- 事务提交
参与者收到commit请求后,会正式执行事务提交操作,并在完成提交之后释放整个事务执行期间占用的事务资源;
- 反馈事务提交结果
参与者在完成事务提交之后,向协调者发送ACK信息;
- 完成事务
协调者接收到所有参与者反馈的ACK信息后,完成事务;
2、中断事务流程
假如任何一个参与者向协调者反馈了NO响应,或者在等待超时之后,协调者尚无法接收到所有参与者的反馈响应,那么就会中断事务
阶段一:
- 事务询问
协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应;
- 执行事务(写本地的Undo/Redo日志)
- 各参与者向协调者反馈事务询问的响应
阶段二:
- 发送回滚请求
协调者向所有参与者发出Rollback请求
- 事务回滚
参与者接收到Rollback请求后,会利用其在阶段一中记录的Undo信息来执行事务回滚操作,并在完成回滚之后释放在整个事务执行期间占用的资源;
- 反馈事务回滚结果
参与者在完成事务回滚之后,向协调者发送ACK信息;
- 中断事务
协调者接收到所有参与者反馈的ACK信息后,完成事务中断;
3、缺点
2PC原理简单,但存在以下缺点:
- 同步阻塞
在二阶段提交的执行过程中,所有参与该事务操作的逻辑都处于阻塞状态,即当参与者占有公共资源时,其他节点访问公共资源会处于阻塞状态;
- 单点问题
若协调器出现问题,那么整个二阶段提交流程将无法运转,若协调者是在阶段二中出现问题时,那么其他参与者将会一直处于锁定事务资源的状态中,而无法继续完成事务操作;
- 数据不一致
在阶段二中,执行事务提交的时候,当协调者向所有的参与者发送Commit请求之后,发生了局网络异常或者是协调者在尚未发送完Commit请求之前自身发生了崩溃,导致最终只有部分参与者收到了Commit请求,于是会话出现数据不一致的现象;
- 太过保守
在进行事务提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的响应信息的话,此时协调者只能依靠自身的超时机制来判断是否需要中断事务,这样的策略过于保守,即没有完善的容错机制,任意一个结点的失败都会导致整个事务的失败。
MySQL Cluster 内部数据的同步就是用的 2PC 协议。
(二)三阶段提交协议(3PC)
3PC,全称 “three phase commit”,是 2PC 的改进版,将 2PC 的 “提交事务请求” 过程一分为二,共形成了由CanCommit、PreCommit和doCommit三个阶段组成的事务处理协议。
三阶段提交升级点(基于二阶段):
- 三阶段提交协议引入 了超时机制;
- 在第一阶段和第二阶段中,引入了一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的;
1、第一阶段(CanCommit 阶段):
协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应;
- 事务询问
协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应;
- 响应反馈
参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则,反馈No
2、第二阶段(PreCommit 阶段):
协调者根据参与者的反应情况来决定是否可以执行事务的PreCommit操作。根据响应情况,有以下两种可能
- Yes
-
- 发送预提交请求:协调者向参与者发送PreCommit请求,并进入Prepared阶段;
- 事务预提交:参与者接收到PreCommit请求后,会执行事务操作,并将undo或redo信息记录到事务日志中;
- 响应反馈:如果参与者成功地执行了事务操作,则返回ACK响应,同时开始等待最终指令;
- No
假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。则有:
- 发送中断请求:协调者向所有参与者发送abort请求
- 中断事务:参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断
3、第三阶段(doCommit 阶段):
该阶段进入真正的事物提交,也可以分为执行提交和中断事务两种情况。
- 执行成功
-
- 发送提交请求:协调者接收到参与者发送的ACK响应,那么它将从预提交状态进入提交状态。并向所有参与者发送doCommit请求;
- 事务提交:参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源;
- 响应反馈:事务提交完之后,向协调者发送ACK响应;
- 完成事务:协调者接收到所有参与者的ACK响应之后,完成事务;
- 中断事务
-
- 发送中断请求:协调者向所有参与者发送abort请求;
- 事务回滚:参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源;
- 反馈结果:参与者完成事物回滚后,向协调者发送ACK信息;
- 中断事务:协调者接收到所有参与者反馈的ACK消息之后,执行事务的中断;
注意:一旦进入阶段三,可能会出现2 种故障:协调者出现问题、协调者和参与者之间的网络故障
如果出现了任一一种情况,最终都会导致参与者无法收到doCommit请求或者abort请求,针对这种情况,参与者都会在等待超时之后,继续进行事务提交,也就出现数据的不一致
4、2PC对比3PC
- 首先对于协调者和参与者都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到参与者的消息则默认失败),主要是避免了参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,无法释放资源的问题,因为参与者自身拥有超时机制会在超时后,自动进行本地commit从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围。
- 通过CanCommit、PreCommit、DoCommit三个阶段的设计,相较于2PC而言,多设置一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的;
- PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的;
3PC协议并没有完全解决数据一致性问题
(三)NWR协议
NWR是一种在分布式存储系统中用于控制一致性级别的一种策略。在亚马逊的云存储系统中,就应用NWR来控制一致性。
- N:在分布式存储系统中,有多少备份数据
- W:代表一次成功的更新操作要求至少有W份数据写入成功
- R:代表一次成功的读数据操作要求至少有R份数据成功读取
NWR值的不同组合会产生不同的一致性效果,当W+R>N的时候,整个系统对于客户端来讲能保证强一致性。
以常见的N=3、W=2、R=2为例:
- N=3,表示,任何一个对象都必须有三个副本
- W=2表示,对数据的修改操作只需要在3个副本中的2个上面完成就返回
- R=2表示,从三个对象中要读取到2个数据对象,才能返回
在分布式系统中,数据的单点是不允许存在的。所以,N必须大于2,N越高,系统的维护和整体成本就越高。工业界通常把N设置为3。
当W是2、R是2的时候,W+R>N,这种情况对于客户端就是强一致性的。
当R+W<=N,无法保证数据的强一致性