这是我参与「第五届青训营 」笔记创作活动的第10天
一、本堂课重点内容:
分布式概述
什么是分布式
分布式系统是计算机程序的集合,这些程序利用跨多个独立计算节点的计算资源来实现共同的目标。可以分为分布式计算、分布式存储、分布式数据库等。
优势: 去中心化 、低成本 、弹性 、资源共享 、可靠性高
挑战: 普遍的节点故障 、不可靠的网络 、异构的机器与硬件环境 、安全
Why
- 使用者视角:
- 数据爆炸,对存储和计算有大规模运用的诉求
- 成本低,构建在廉价服务器之上
- 学习者视角:
- 后端开发必备技能
- 帮助理解后台服务器之间协作的机理(了解一致性协议)
常见的分布式系统
- 分布式存储
- Google File System (GFS) : google分布式文件系统
- Ceph : 统一的分布式存储系统
- Hadoop HDFS : 基于GFS架构的开源分布式文件系统
- Zookeeper : 高可用的分布式数据管理与系统协调框架
- 分布式数据库
- Google Spanner : google可扩展的、全球分布式的数据库
- TiDB : 开源分布式关系型数据库
- HBase : 开源Nosql数据库(构建在HDFS之上)
- MongoDB : 文档数据库
- 分布式计算
- Hadoop : 基于MapReduce分布式计算框架
- Spark : 在Hadoop基础之上,使用内存来存储数据
- YARN : 分布式资源调度
系统模型
故障模型
根据分布式系统中会出现的常见故障,总结了故障模型。
-
六种故障模型,从处理的难易程度分类(而不是严重程度)
- Byzantine failure(拜占庭故障):节点可以任意篡改发送给其他节点的数据,是最难处理的故障
- Authentication detectable byzantine failure (ADB):(拜占庭特例)节点可以篡改数据,但不能伪造其他节点的数据
- Performance failure:节点未在特定时间段内收到数据,即时间太早或太晚
- Omission failure:节点收到数据的时间无限晚,即收不到数据
- Crash failure:节点停止响应,持续性的故障
- Fail-stop failure:错误可检测,是最容易处理的故障
总结以上六种故障模型,分别是正确性、时间、状态、原因四个维度的原因。
- 故障模型举例,按照模型分类
-
磁盘故障。如:磁头不寻道、盘片不转、磁介质损伤等。年发生率1-2%。Fail-stop
-
磁盘坏道、坏块。磁头划伤引起坏道,或受宇宙射线影响晶体管产生位反转。Fail-stop,ADB
-
服务器主板、板卡故障。可能是风扇故障,或灰尘引起的短路或SCSI/RAID卡造成的死机。Crash
-
网络故障。电源故障、背板故障等,网卡位反转、网络流量大造成大量丢包等。Byzantine,Omission
-
网络分区。网络引起节点形成不同的子集,子集中网络相通,子集间网络不通。Performance
-
内存故障。内存出错造成的数据被篡改,分为UE、CE两种。ADB
-
线缆故障。服务器光模块频繁up或down。Performance,Omission
-
内核崩溃。内核内部的致命错误,产生的kernel panic。Crash
-
CPU故障。年故障率接近1%。Omission、Crash
-
电源故障。服务器失去电力支撑。Omission
-
软件故障。如: 进程crash、内存踩坏、状态不一致、配置错误、软件bug等。Byzantine,Crash等
-
拜占庭将军问题
分布式中的一个基本问题。实际上工程中针对消息篡改(出错)是通过加密的方式解决的,所以通常不考虑拜占庭故障。
-
两将军问题
-
定义:
- 两支军队的将军只能派信使穿越敌方领土互相通信,以此约定进攻时间。该问题希望求解如何在两名将军派出的任何信使都可能被俘虏的情况下,就进攻时间达成共识
-
结论:
- 两将军问题是被证实无解的电脑通信问题,两支军队理论上永远无法达成共识
-
TCP 三次握手是在两个方向确认包的序列号,增加了超时重试, 是两将军问题的一个工程解。
-
-
三将军问题:
- 两个“忠将”A和B,一个“叛徒”C,互相传递消息,消息可能丢失,也可能被篡改,当有一个将军是“叛徒”(即出现拜占庭故障)时,整个系统无法达成一致。
- 由于“叛徒”C的存在,将军A和将军B获得不同的信息。这样将军A获得2票进攻1票撤退的信息,将军B获得1票进攻2票撤退的信息,产生了不一致(0、2、3个叛徒都能达成一致)
-
四将军问题(考虑当4个将军,有1个叛徒的场景,且增加一轮协商):
-
将军D作为消息分发中枢(D不投票),约定如果没收到消息则执行撤退
-
步骤:
- 如果D为“叛徒”,ABC无论收到任何消息,总能达成一致
- D为“忠将”,ABC有2人将D的消息进行正确的传递,同样能保证最终决策符合大多数。
-
进而能够证明,当有3m+1个将军,m个“叛徒”时,可以进行m轮协商,最终达成一致
-
共识和一致性
不同客户端A和B看到客户端C写入,因为时机的不同,产生数据读取的偏差。引导出最终一致性的详细说明。比如:
初始x = 0, A和B读取 x,C写入x。
-
客户端A读到x=0,当客户端C正在写入时,客户端A和B可能读到0或者1。但是当C写入完成后,A和B最终能读到一致的数据,我们称这样的一致性为Eventuallyconsistent(最终一致性)
-
当客户端A读到更新的版本x=1后,及时将消息同步给其他客户端,这样其他客户端立即能获取到x=1。我们称这样的一致性为Linearizability (线性一致性)
如果要保证“线性”一致性,多个节点间势必需要进行协商,以寻求一致。这样增加了延迟,系统可用性便会受损。
时间和事件顺序
1978年Leslie Lamport发表《Time, Clocks, and the Ordering of Events in a Distributed System》
-
定义了计算机系统中的时间和事件顺序,引入happened before和并发的定义,可以以此对分布式系统中的事件进行推导
-
根据上述推导,创造了Lamport逻辑时钟的概念,这个概念在分布式理论中具有革命性的意义,帮助我们在一系列分布式事件当中梳理出逻辑的先后关系。利用逻辑时钟,我们可以对整个系统中的事件进行全序排序
理论基础
本部分介绍分布式中三大理论。分别是 CAP理论、ACID理论、BASE理论。
CAP理论
CAP理论往往运用于数据库领域,同样可以适用于分布式存储方向。
- CAP的定义
-
C:一致性(Consistence),指数据在多个副本之间能够保持一致的特性 (严格的一致性)
-
A:可用性(Availability),指系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应(但是不保证获取的数据为最新数据)
-
P:分区容错性(Network partitioning),分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障。
-
CAP理论的结论为,三者无法同时达到,所以便产生如下三种组合:
-
CAP诞生了三类系统:
-
CA系统:放弃分区容错性,加强一致性和可用性,其实就是传统的单机数据库的选择
-
AP系统: 放弃一致性 (这里说的一致性是强一致性) ,追求分区容错性和可用性,例如一些注重用户体验的系统(不少nosql存储系统采用)
-
CP系统:放弃可用性,追求一致性和分区容错性,例如与钱财安全相关的系统
-
ACID理论
事务是数据库系统中非常重要的概念,它是数据库管理系统执行过程中的一个逻辑单元,它能够保证一个事务中的所有操作要么全部执行,要么全都不执行。(比如A转账给B一万,数据库需要给A减去1W,给B加上1W,两个操作为一个事务)
ACID理论是针对CA系统而言的,通常在数据库中具有广泛意义。
数据库事务拥有四个特性,ACID即分别是
-
原子性 (Atomicity) 是指事务包含的所有操作要么全部成功,要么全部失败回滚
-
一致性 (Consistency) 是指事务必须使数据库从一个一致性状态变换到另一个一致性,也就是说一个事务执行之前和执行之后必须处于一致性状态。(数据库里的一致性指的是事务的一致性,CAP里的一致性是线性一致性)
-
隔离性 (lsolation) 是当多个用户并发访问数据库时,不能被其他事务的操作所干扰,多个数据库为每一个用户开启的事务,并发事务之间要相互隔离
-
持久性(Durability) 是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
BASE理论
BASE理论是针对AP系统而言的,其来源于对大型互联网分布式实践的总结。
-
Basically Available(基本可用):假设系统,出现了不可预知的故障,但还是能用
-
Soft state(软状态):允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时
-
Eventually consistent(最终一致性):系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态
分布式事务
跨节点(跨数据库)之间的事务为分布式事务。系统中尽量避免分布式事务,因为难处理。
二阶段提交
二阶段提交(Two-phase Commit):为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种演算法。
- 三个假设
- 引入协调者(Coordinator) 和参与者 (Participants) ,互相进行网络通信
- 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上
- 所有节点不会永久性损坏,即使损坏后仍然可以恢复
- 异常流程
- Coordinator不宕机,Participant宕机。如下图所示,需要进行回滚操作情况
- Coordinator宕机,Participant不容机。i可以起新的协调者,待查询状态后,重复二阶段提交情况
- Coordinator宕机,Participant宕机。无法确认状态,需要数据库管理员的介入,防止数据库进入一个不一致的状态
回滚: 在Prepare阶段,如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。
-
两阶段提交需解决的问题:
- 性能问题:需要多次网络通信,资源需要等待并锁定
- 新协调者:如何确定状态选出新协调者
- Commit阶段网络分区带来的数据不一致:非所有节点都收到Commit请求
三阶段提交
- 针对两阶段提交的补充,将两阶段提交中的Prepare阶段,拆成两部分:CanCommit和PreCommit机制
- CanCommit阶段:询问是否可以执行;PreCommit阶段:重新确认是否可以执行
- DoCommit阶段:向所有人提交事务
解决了两个问题
- 单点故障问题
- 阻塞问题
另外引入超时机制,在等待超时之后,会继续进行事务的提交
MVCC
在数据库中,锁的使用是非常常见的,对数据加锁是为了解决事务的隔离性问题,让事务之间相互不影响,每个事务进行操作的时候都必须先对数据加上一把锁,防止其他事务同时操作数据。提交或回滚事务会释放锁。
-
悲观锁和乐观锁
- 悲观锁:操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据
- 乐观锁:不会上锁,只是在执行更新时判断别人是否修改数据,只有冲突时才放弃操作
- 使用MVCC代替悲观锁和乐观锁
MVCC是一种并发控制的方法,维持一个数据的多个版本使读写操作没有冲突。所以既不会阻塞写,也不阻塞读。MVCC为每个修改保存一个版本,和事务的时间戳相关联。可以提高并发性能,解决脏读的问题。
使用MVCC后,每次修改都会产生一个版本,那么如何获取特定版本的数据:
-
版本的选取:使用物理时钟或逻辑时钟
- 物理时钟:提供TrueTime API,有Master节点维持一个绝对时间,保证各个服务器之间时钟误差控制在ϵ内,通常ϵ<7ms。
- 逻辑时钟:中心化授时的方式--时间戳预言机(TSO),好处是无需硬件的支持
共识协议
Quorum NWR模型
分布式系统中常见的模型之一。
-
三要素:
- N:在分布式存储系统中,有N份备份数据
- W:代表一次成功的更新操作要求至少有w份数据写入成功
- R: 代表一次成功的读数据操作要求至少有R份数据成功读取
为了保证强一致性,需要保证 W+R>N (必要条件,反证法)
-
Quorum NWR模型将CAP的选择交给用户,是一种简化版的一致性模型
-
引起的并发更新问题
- 如果允许数据被覆盖,则并发更新容易引起一致性问题
RAFT协议
Raf协议是一种分布式一致性算法(共识算法),即使出现部分节点故障,网络延时等情况,也不影响各节点,进而提高系统。一定意义上讲,RAFT也使用了Quorum机制。的整体可用性。Raftt是使用较为广泛的分布式协议。
-
三种角色
-
Leader - 领导者:通常一个系统中是一主 (Leader) 多从(Follower) 。Leader 负责处理所有的客户端请求,并向Follower同步请求日志,当日志同步到大多数节点上后,通知Follower提交日志
-
Follower - 跟随者:不会发送任何请求。接受并持久化Leader同步的日志,在Leader告知日志可以提交后,提交日志。当Leader出现故障时,主动推荐自己为Candidate。
-
Candidate - 备选者:Leader选举过程中的临时角色。向其他节点发送请求投票信息。如果获得大多数选票,则晋升为Leader。
-
-
四种定义:
- Log(日志):节点之间同步的信息,以只追加写的方式进行同步,解决了数据被覆盖的问题
- Term(任期号):单调递增,每个Term内最多只有一个Leader
- Committed:日志被复制到多数派节点,即可认为已经被提交
- Applied:日志被应用到本地状态机:执行了log中命令,修改了内存状态
-
状态转移:
-
-
Leader选举过程:(在一个任期内每个参与者最多投一票 (持久化))
- 初始全部为Follower
- Current Term + 1
- 选举自己
- 向其它参与者发起RequestVote请求,retry直到
- 收到多数派请求,成为Leader,并发送心跳
- 收到其它Leader的请求,转为Follower,更新自己的Term
- 收到部分,但未达到多数派,选举超时,随机timeout开始下一轮
-
Log Replication(同步log)过程:
- 新Leader产生,Leader和Follower不同步,Leader强制覆盖Followers的不同步的日志
-
切主:当Leader出现问题时,就需要进行重新选举
- Leader发现失去Follower的响应,失去Leader身份
- 两个Follower之间一段时间未收到心跳,重新进行选举,选出新的Leader,此时发生了切主
- Leader自杀重启,以Follower的身份加入进来
问题: 老leader未失去身份,新leader已经选出,产生了“双主"该如何解决呢?
-
Stale读(旧读):
-
问题:发生Leader切换,old leader收到了读请求。如果直接响应,可能会有Stale Read出现
-
解决方案:
- 默认自己是leader:读操作在lease timeout内,不是则发起一次heartbeat。等待Commit Index应用到状态机。
- Election timeout > lease timeout: 新leader_上任,自从上次心跳之后一定超过了Electiontimeout,l日leader大概率能够发现自己的Lease过期
-
Paxos协议
-
Paxos算法与RAFT算法区别:
- Multi-Paxos 可以并发修改日志,而Raft写日志操作必须是连续的
- Multi-Paxos 可以随机选主,不必最新最全的节点当选Leader
-
优劣势
- 优势:写入并发性能高,所有节点都能写
- 劣势:没有一个节点有完整的最新的数据,恢复流程复杂,需要同步历史记录
分布式实践
MapReduce
设计一个MapReduce系统,统计超大文本文件中每个单词出现次数。
在Hadoop中Input是放在HDFS(分布式文件系统)。
- Mapper : 将输入分解为多个Job来并行处理。彼此间几乎没有依赖关系
- Shuffler : 将maper结果打乱,防止数据倾斜
- Reducer : 对map阶段的结果进行全局汇总
容错:
- 1.Mapper故障:由中心化节点重新发起调度,新起Mapper重跑job
- 2.Reducer故障:重跑Mapper,代价大
分布式KV
设计一个简易的分布式键值系统,来存储大规模KV对(key-value),要求具备弹性的能力和达成线性一致。
-
架构 : 将海量结构化数据根据Key分成不同的Region,每个Region构建一个单机KV数据库,Region之间形成Raft Groups做到强一致
-
弹性 : 当出现局部Key热点或数据膨胀时Region可以进行Split操作,分成两个子Region,反之收缩时进行Merge操作
-
容错 : 当Node故障时,通过Raft Learner模式进行数据修复