本文内容总结自 字节跳动青年训练营 第五届后端组
分布式理论初探
一、概述
分布式系统是计算机程序的集合,这些程序利用横跨多个独立计算节点的计算资源实现共同目标,可分为分布式计算、分布式存储、分布式数据库。
其优势是:去中心化、低成本、弹性、资源共享、可靠性高
但是也有挑战:
- 普遍的结点故障
- 不可靠的网络
- 异构的机器与硬件环境
- 安全
常见分布式系统
二、系统模型
2.1 故障类型
故障类型可以通过正确性、时间、状态三个维度去分析
- Byzantine failure:结点可以任意篡改发送给其他节点的数据,是一种正确性故障
- Authentication detectable byzantine failure: Byzantine failure的特例,节点可以篡改数据,但是不可以伪造其他节点的数据
- Performance failure: 结点未在指定时间段内收到数据,也就是时间过早或过晚,会影响性能或者直接不可用
- Omission failure: 节点收到数据时间无限晚,也就是无法接收数据,是一种时间故障
- Crash failure: 在Omission failure上,增加了结点停止响应的假设,也就是持续Omission failure,比如说宕机。这属于时间故障,同时故障状态不可知
- Fail-stop failure: 在Crash failure的基础上增加了错误可检测的假设
工作中的故障以及可能对应的类型
2.2 拜占庭将军问题
拜占庭将军问题如下:
有两个将军从东面和西面包围了一座城池,他们需要派出信使商定明天早上什么时候一同进攻,但是派出的信使有一定概率在经过城池的时候被抓走。那么就有两种方法:
方法一:同时发出n个信使,任何一个到达对方军队均为成功,但是依然存在n个信使全部被抓的可能性
方法二:效仿TCP链接,设置一个超时时间,发送后没有在一定时间内返回,则增派信使
然而两种方法都无法保证双方一定达成共识。具体为何我不太说得明白,可以去查询一些其他资料
拜占庭将军Plus
上述的拜占庭将军问题是最原始的问题,下面的拜占庭将军Plus更适合用于解释分布式系统下的情况。有3个将军a,b,c投票决定是进攻还是撤退,但是其中将军b是叛徒,他和a说他要进攻,和b说他要撤退。如果此时a的意愿是进攻,而b的意愿是撤退,那么在a的视角下,有2票进攻和一票撤退,那么他会发起进攻;在b的视角下,有2票撤退,一票进攻,则b会撤退,这种情况下他们会被逐个击破。
但是如果再增加一个将军,也就是有a.b.c.d四个将军,一个叛徒,那么无论谁是叛徒,都不会影响最终的投票结果,可以自己写一写看一看。
这种情况下很类似于分布式系统中有节点发生故障,向不同的其他节点发送不一致的信息的情况,这会导致分布式系统故障。而运用数学可以证明,当有3m+1个将军,m个叛徒的时候,可以增加m轮协商,最终达成一致
拜占庭将军问题较难解决,只能增加纠错信息、加密来改善
2.3 共识和一致性
一致性
当客户端a读到x=0,客户端c正在写入x=1的时候,客户端a和b可能读取到0或者1,但是当c写入完成后,a和b读取到的x的数据是一致的,这被称为最终一致性
当客户端a读到更新版本的x=1之后,及时将消息同步给其他客户端,这样其他客户端可以立刻知道x=1,这样的一致性为线性一致性。为了实现线性一致性,多个节点之间那就必须进行协商,这会增加延迟,降低系统性能,但是可以获得更高的一致性
并发和事件顺序
如果a和b是相同节点上的两个时间,a在b之前发生,则定义为 a → b a\to b a→b。如果a和b是没有先后次序之分的,也就是 a ↛ b a \nrightarrow b a↛b并且 b ↛ a b \nrightarrow a b↛a,则称a和b是并发的,此处并发和操作系统中的定义不一样
三、理论基础
3.1 CAP理论
在分布式系统中,CAP不能完全同时实现一致性、可用性和分区容错性
CA:放弃分区容错性,加强一致性和可用性,就是传统的单机数据库,不进行分布式部署
AP:放弃一致性(指的是强一致性)。追求分区容错和可用性,能有较高的性能,例如一些注重用户体验的系统
CP:放弃可用性,追求一致性和分区容错性,比如和钱财安全相关的系统
比如在网络分区的情况下(也就是在选择了分区容错性的情况下),只能再可用性和一致性中二选一,比如有两个节点P1和P2共享变量x=0,P1执行x=1的操作,并试着将x=1同步到P2中,但是若此时长时间同步失败,那么有两种策略:
- 选择可用性:
结点P1和P2继续向后执行,但是P1中x=1,P2中x=0,失去了数据一致性
- 选择一致性
同步失败使得P2直接拒绝服务了,此时为了保证数据一致性,系统中只有1个结点可用了,丧失了可用性
3.2 ACID理论
事务是数据库中非常重要的概念,是数据库管理系统执行过程的逻辑单元,事务有ACID四个特性,
Atomicity:原子性
事务中的操作要么全部执行要么全部不执行
Consistency:一致性
事务执行的结果必须是使得数据库从一个一致性状态变到另一个一致性状态,也就是说一个事务执行前和执行后都需要处于一致性状态。事务的执行必须是一气呵成的。可见一致性和原子性密切相关
Isolation:隔离性
一个事务的执行不能被其他事务所干扰,就是一个事务的内部操作及其使用的数据对其他并发事务时隔离的。
Durability:持续性 一个事务一旦提交,对数据库中数据的改变应该是永久性的
ACID实现了一致性和可用性
3.3 BASE理论
BASE理论是对CAP中一致性和可用性的权衡,其来源于对大型互联网分布式实践的总结,主要可以用于对一致性要求没有那么高,需要兼顾一致性和可用性的场景。其核心思想是
Basically Available(基本可用):若系统出现了不可预知的故障,但还能使用,那么它的性能会降低,可能部分功能不可用,但不会轻易崩溃
Soft State(软状态):允许系统中的数据存在中间状态,也就是允许系统在多个不同节点的数据副本存在不一致的数据时延
Eventually Consistent(最终一致性):虽然数据有撞见状态,数据最终一定是一致的
四、分布式事务
4.1 二阶段提交
二阶段提交是基于分布式系统架构下的所有结点在进行事务提交时保持一致性而设计的一种演算法
在二阶段提交的分布式系统中,有协调者(Coordiator)节点和参与者(Participants)结点,其中协调者负责协调所有参与者的事务提交的一致性。搜右节点都采用预写式日志,并且日志被写入后立刻被保存在可靠的存储设备上。
二阶段提交的两个阶段分别是Perpare阶段和Commit阶段
假设A要向B转账1万块,那么协调者向A发送准备扣款1万的Prepare,向B发送准备入账1万的请求,此时完成了Prepare阶段,但转账动作尚未完成。在Commit阶段,协调者向A和B发送Commit,然后A和B完成各自的动作并且返回Ack,完成了转账操作。在一切顺利的时候似乎二段式并没有什么特殊的作用,但是考虑以下的情景:
1)Coordinator不宕机,但是Participant B宕机
A要向B转账1万块,在Prepare阶段,此时A已经做好了扣款准备,但是B直接宕机了,并没有做好收款准备,此时则协调者发出回滚指令,回滚到最初状态
2)Coordinator宕机,但是Participant不宕机
需要更换另一个Coordinator节点,新的Coordinator没有各个Participant的状态信息,因此需要逐个询问获取信息后,再做决策
3)Coordinator和Participant都宕机
无法确认状态,需要数据库管理员介入,防止系统出现数据不一致
在单机时代,实际上只需要直接一个操作就可以完成A向B转账,但是在分布式上则无法这样做。
4.2 三阶段提交
三阶段提交将两阶段提交的Prepare拆分成了CanCommit和PreCommit两个部分。其执行流程如下
这解决了两个问题:
1.阻塞问题
2.单点故障问题
另外引入超时机制,在DoCommit等待超时之后,会继续进行事务的提交。在二阶段提交中,如果最后的Ack发送失败,会回滚整个事务,这样的开销是非常大的。而三阶段提交的DoCommit如果超时,那还是会继续提交,而不进行开销较大的回滚操作,如果出现了数据错误,后面再回滚
4.3 MVCC
锁对性能是有一定的影响的,是一种牺牲可用性换数据一致性的操作。
五、公司协议
QuorumNWR模型
N表示在分布式系统中有几份备份数据
W表示一次成功更新操作至少有几份数据写入成功
R表示一次成功读数据操作要求至少有R份数据成功读取
为了保证强一致性,需要保证W+R>N
该模型CAP选择交给用户,是一种简化的一致性模型
RAFT协议
这是一种分布式一致性算法,也就是即便出现部分节点故障、网络时延等情况,也不影响各个节点,进而提高系统的整体可用性。这是使用较为广泛的协议。其中有三种角色:
Leader:通常是一主多从的,Leader负责处理所有的客户端请求,并且向Follower同步请求日志,当日志同步到大多数节点上之后,通知Follower提交日志
Follower:跟随者,不会发送任何请求,接受并且持久化Leader的同步日志。当Leader出现故障的时候,主动推荐自己成为Candidate
Candidate:Leader选举过程中的临时角色,向其他节点发送请求投票信息,如果获得多数选票则晋升为Leader
下面是三个角色之间的状态机转换图
想要看懂这幅图还需要了解以下概念:
- Log:节点之间同步的信息,解决了数据被覆盖的问题
- Term 任期号:单调递增,一个Term中只能有一个Leader
- Committed: 日志被复制到多数派节点,就可以认为已经被提交
刚开始都大家都是Follower,如果到了选举期则转化为Candidate,然后进行选举,选出一个Leader,其他的Candidate变回Follower,如果任期到了或者Leader宕机,那么Leader变回Follower,然后重新选举
由于Leader的数据一定是最新数据,因此需要读数据只需要读取Leader的数据,而不需要像Quorum那样读取数份e’m