这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天
概述
分布式系统是计算机程序的集合,这些程序利用跨多个独立计算节点的计算资源来实现共同的目标。可以分为分布式计算、分布式存储、分布式数据库等
优势:
- 去中心化
- 低成本
- 弹性
- 资源共享
- 可靠性高
挑战:
- 普遍的单点故障
- 不可靠的网络
- 异构的机器与硬件环境
- 安全
常见的分布式系统
系统模型
故障模型
故障时常在发生,所以不得不研究故障的类型
Byzantine failure(拜占庭故障):节点可以任意篡改发送给其他节点的数据
Authentication detectable byzantine failure(ADB) :拜占庭故障的特例,节点可以篡改数据,但不能伪造其他节点的数据
Performance failure:节点未在特定时间段内收到数据,即时间太早或太晚
Omission failure:节点收到数据的时间无限晚,即收不到数据
Crash failure:在omission failure的基础上,增加了节点停止响应的假设,也即持续性地omission failure(只知道原因,不知道状态)
Fail-stop failure:在Crash failure的基础上增加了错误可检测的假设(既知道状态,也知道原因)
拜占庭将军问题
引入:两将军问题:两支军队的将军只能拍信使穿越敌方领土互相通信,以此约定进攻时间
结论:两将军问题是被证实为无解的电脑通信问题,两支军队理论上永远无法达成共识
方案一:同时发送N个信使,任何一个达到对方军队,都算成功
方案二:设置超时时间,发送后未在一定时间返回,则加派信使
共识与消息传递的不同:即使保证了消息传递成功,也不能保证达成共识
TCP三次握手是在两个方向确认包的序列号,增加了超时重试,是两将军问题的一个工程解
如果考虑更加普适的场景,例如3个将军ABC互相传递消息,也可能被篡改,当有一个将军是叛徒(即出现拜占庭故障),整个系统无法达成一致
解法是再引入一个将军D,作为消息分发中枢。
- 如果D为叛徒,ABC无论收到任何消息,总能达成一致
- 如果D不是叛徒,假设AB不是叛徒,C是叛徒。ABC中有两人将D的消息进行正确的传递,同样能保证最终觉得符合大多数
最后证明当有3m + 1个将军,其中有m个叛徒时,可以增加m轮协商,最终达成一致
共识和一致性
如果要保证“线性”一致性,多个节点间势必要进行协商,以寻求一致性。这样增加了延迟,系统可用性便会受损
时间和事件顺序:
理论基础
CAP理论
C:一致性,数据在多个副本之间能够保持一致的特性
A:可用性,系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应,但是不保证获取的数据为最新数据
P:分区容错性,分布式系统在遇到任何网络分区故障的时候,仍能对外提供一致性和可用性的服务,除非整个网络环境都发生了故障
在网络发生分区的情况下,我们必须在可用性和一致性之间做出选择,近似解决办法:把故障节点的负载转移给备用节点负责
用多个节点一个master和多个备用节点backup,当master故障后转移到backup节点
ACID理论
事务具有四个特性:
- 原子性:事务包含的所有操作要么全部成功,要么全部失败回滚
- 一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说事务执行之前和事务执行之后都必须处于一致性状态
- ‘隔离性:多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
- 持久性:一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作
BASE理论
互联网业务不一定都对一致性有很高的要求
Base理论是对CAP中一致性和可用性权衡的结果
分布式事务
二阶段提交
二阶段提交:为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种演算法
三个假设:
- 引入协调者和参与者,互相进行网络通信
- 所有节点采用预写式日志,且日志被写入后即被保持在可靠的存储设备上
- 所有节点不会永久性损坏,即使损坏后仍然可以恢复
可能出现的情况:
-
协调者不宕机,参与者宕机,需要进行回滚操作
-
参与者不宕机,协调者宕机。可以起新的协调者,待查询状态后,重复二阶段提交
-
双方都宕机。需要数据库管理员的介入
两阶段提交需要注意的问题:
- 性能问题
- 协调者单点故障的问题
- 网络分区带来的数据不一致。一部分参与者收到了Commit消息,另一部分没收到Commit消息,会导致了节点之间数据不一致。解决方法:用锁
日志被保存在“可靠”的存储设备上,如何保证?
- 单机数据库时代用高可用的硬件保证,IOE来做数据库
- 分布式时代使用分布式文件系统、KV系统等
参与者Commit了,但Ack消息协调者没收到,怎么办?
会带来性能浪费,继续回滚
三阶段提交
将上述二阶段提交的Prepare阶段拆成两部分:CanCommit和PreCommit机制。可以解决单点故障问题和阻塞问题
另外引入超时机制,在等待超时之后,会继续进行事物的提交
但是仍然没解决二阶段提交的性能问题和网络分区带来的数据一致性问题
MVCC
锁:
-
悲观锁:操作数据时直接把数据锁住,知道操作完成后才会释放锁;上锁期间其他人不能修改数据
-
乐观锁:不会上锁,只是在执行更新时判断别人是否修改数据,只有在冲突时才会放弃操作
MVCC是一种并发控制的方法,维持一个数据的多个版本使读写操作没有冲突。
MVCC为每一个修改保存一个版本,和事物的时间戳相关联,可以提高并发性能,解决脏读的问题
另外一种时间戳的实现:时间戳预言机(TSO),采用中心化的授时方式,所有协调者向中心化节点获取时钟
共识协议
Quorum NWR模型
- N:在分布式系统中,有多少分备份数据
- W:代表一次成功的更新操作要求至少有w份数据写入成功
- R:代表一次成功的读数据操作要求至少有R份数据成功读取
为了保证强一致性,需要满足
Quorum NWR模型将CAP的选择交给用户,如可以设置N、W、R的值
RAFT协议
是一种分布式一致性算法(共识算法),即使出现部分节点故障,网络延时等情况,也不影响个节点,进而提高系统的整体可用性。Raft时使用较为广泛的分布式协议
Leader:领导者,通常一个系统时一主多从。Leader负责处理所有客户端的请求,冰箱Follower同步请求日志,当日志同步到大多数节点后,通知Follower提交日志
Follower:跟随者,不会发送任何请求。接受并持久化Leader同步的日志,在Leader告知日志可以提交后,提交日志。当Leader出现故障时,主动推荐自己为Candidate
Candidate:备选者,Leader选举过程中的临时角色。向其他节点发送请求投票信息。如果获得大多数选票,则晋升为Leader
Log:日志,节点之间同步的信息,以只追加写的方式进行同步,解决了数据被覆盖的问题
Term:任期号:单调递增,每个Term内最多有一个Leader
Committed:日志被复制到多数派节点,即可认为已经被提交
Applied:日志被应用到本地状态机,执行了log中命令,修改了内存状态
综上,RAFT只需要写两份,读一份,所以性能很好
RAFT的运作机制:
Leader的选举过程:
心跳是指Leader和Followers之间的周期性通信
Log Replication过程:
两个规则:
- 在一个任期内每个参与者最多投一票
- 要成为Leader,必须拿到多数选票
切换Leader:
如果出现网络分区,数据没有同步,产生”双主“,如何解决?
Stable读:
Paxos协议
Paxos算法与RAFT算法区别:
- Multi-Paxos 可以并发修改日志,而Raft写日志操作必须是连续的
- Multi-Paxos 可以随机选主,不必最新最全的节点当选Leader
优劣势
- 优势:写入并发性能高,所有节点都能写
- 劣势:没有一个节点有完整的最新的数据,恢复流程复杂,需要同步历史记录
分布式实践
MapReduce
Mapper:将输入分解为多个Job来并行处理。彼此之间几乎没有依赖关系
Shuffler:将maper结果打乱,防止数据倾斜
Reducer:对map阶段的结果进行全局汇总
分布式KV
架构:将海量结构化数据根据Key划分成不同的Region,每个Region构建一个单机KV数据库,Region之间形成Raft Groups,做到强一致
容错:当Node故障时,通过Raft Learner模式进行数据修复
弹性:当出现局部key热点或者数据膨胀时,Region可以进行Split操作,分成两个子Region,反之收缩进行Merge操作