分布式理论1
为了能有一份工作,包上各种公司的大腿,痛定思痛从来一遍分布式学习,也会对之后的写的代码有一定的提升。PLUS我手里有两台服务器闲着也是闲着,不如先玩玩喽
网课链接:https://www.bilibili.com/video/BV1Pf4y1W7oH
基础概念:CAP理论
-
Consistency(一致性):所有的节点上的数据时刻保持同步,数据保持修改成功或修改失败的一致性
-
Available(可用性):每个请求都能接受到一个响应,无论响应成功或失败,额额不是被阻塞等待
-
Partion-tolerance(分区容错):在网络分区的情况下,系统应该能持续提供服务,即使系统内部有消息丢失
任何分布式系统在可用性、一致性、分区容错性方面,不能兼得,最多只能得其二,因此,任何分布式系统的设计只是在三者中的不同取舍而已。
由于异步通信中不存在任何一致性的分布式算法的证明,现在一般分布式追求CP或者AP因为分区的存在,有隔离的数据式无法进行数据一致性的更新(追求CP),或等待网络恢复数据同步后再提供服务(追求AP)
拓展:FLP Impossible
FLP Impossible 证明了CAP三者不可兼得(参考网址:https://blog.youkuaiyun.com/chen77716/article/details/27963079)
分布式的算法与定理均假定在具体的分布模型之下,所以FLP所在的模型假设:
- 异步通讯:没有时钟,不能同步消息,消息乱序,存在拥塞延时现象(这些原来TCP协议可以解决,但总会存在无法联网的分区状态,如手机关机,没有信号等等)
- 通讯健壮:data不论如何(即使延时较久)一定会被送达,且仅会被接受一次
- 进程失败将导致宕机(整个阻塞住无法继续)
- 失败进程数量:最多一个进程失败(理想情况,如果连理想情况都证明失败更不用说现实模型了)
衡量分布式算法是否正确的三个因素:
- Termination(终止性):非失败进程可以选择终止,指算法不能无限时间的循环下去
- Agreement(一致性): 所有的进程必须做出相同的决议,不能产生不同的结果,否则结果不可信
- Validity(合法性) : 进程的决议值,必须格局其他进程提交的请求值,排除自身进程初始值的干扰
详细例子请看上文链接,还是比较通俗的
注意,拥塞与进程失败由于存在延迟的情况导致无法判断
Configuration:前面已经提到,所有进程的状态集合,进程的状态包括初始值、决议值、消息队列的内容
初始Configuration:各个进程初始值是随机的、消息队列为空、决议为空的开始状态
证明关键:证明在初始Configuration随机(进程的结果也不都由Configuration决定,换言之证明进程无法通过初识的Configuration直接得出确定的提交结果,而且存在消息延迟并且算法可终止情况下结果式随机的)的情况下,存在结果Configuration无法预测的随机情况,没有任何条件能够避免,即没有一致性的分布式算法。所以CAP最多得其二,详见FLP证明
拓展:Paxos算法:
(这里现卖个关子,因为我还没有学到所以之后一定)
Paxos算法是基于消息传递且具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一。然而,Paxos算法也因为晦涩难懂而臭名昭著。
基础概念:BASE理论
BASE理论是在CAP的基础上降低了对可用性和一致性的要求。
- 基本可用:允许服务降级(系统中模块分级加载,不重要的模块延迟响应),允许延迟
- 软状态:系统数据存在中间状态,中间状态不会影响系统可用性
- 最终一致性:节点之间数据同步可能存在时延,但最终必须保证数据的一致性
拓展:数据一致性模型(不同需求下的多种选择):
- 强一致性:写入之后须先进行数据的一致性处理后载恢复服务,节点间数据任何时刻保持一致
- 最终一致性: 结点间的数据同步允许存在延时,但是最终状态必须一致。存在的延时时间为不一致性窗口
- 因果一致性: 有因果关系的操作顺序需要得到保证(接口调用,父子类的数据同步)
- 会话一致性:载同一会话中Session 数据保持最新读写操作的更新
Quorum、WARO机制
-
WARO协议
是一种简单的副本控制协议,当 Client 请求向某副本写数据时(更新数据),只有当所有的副本都更新成功之后,这次写操作才算成功,否则视为失败。WARO带来的影响是写服务的可用性较低,因为只要有一个副本更新失败,此次写操作就视为失败了,但是读取时只要有任意数据副本存活即可读取数据。
-
Quorum机制:
假设有 N 个副本,更新操作 wi 在 W 个副本中更新成功之后,则认为此次更新操作 wi 成功,把这次成功提交的更新操作对应的数据叫做:“成功提交的数据”。对于读操作而言,至少需要读 R 个副本,其中,W+R>N ,即 W 和 R 有重叠,一般,W+R=N+1。Quorum必须读取所有未更新的副本与至少一个已更新的副本来判断哪个/些携带最新数据副本确认最新的数据(引入数据的版本号,也就是时间戳来判断最新与否)。
拓展: 时间戳的安全性:
暂无,等待补充,时间戳目前一般都是基于可信第三方添加的数据水印,但是时间抽在乱序情况下曾导致过去中心化的以太坊的安全性问题,如重入攻击等,后续会进行补充)
刁钻:强一致性Paxos算法:
补充Paxos博客园链接:https://www.cnblogs.com/linbingdong/p/6253479.html
引言:paxos算法是目前公认的最好用的分布式数据同步算算法(没有之一),其目的是满足在可能出现消息时延,阻塞,机器宕机,进程崩溃的情况下依然快速进行强一致数据的算法。paxos是其他框架的思想基础。
paxos解决的是不同节点之间的指令(data)一致,多指令通过多次执行paxos保证一致。朴素paxos不保证指令顺序一致
注:每轮paxos算法只能保证一个value的统一,多个value值需要多轮paxos
在Paxos假定的环境下有三种角色:
- Proposer:提出propose。只要提出的propose被半数以上的Acceptor认可,即认为该提案的value被选定
- Acceptor: Acceptor接受某个天,认为该提案的value被认可
- Learners: Acceptor告诉Learners记录哪个value, 哪个value就被认可
一个进程可以充当多种角色。整个过程围绕Propose(提案)来完成。Propose中包含我们想要一致性化的value.
Proposer可以提出(propose)提案;Acceptor可以接受(accept)提案;如果某个提案被选定(chosen),那么该提案里的value就被选定了。
在一组Proposer提出了一组Value之后,Paxos需要保证只有Value只有一个被认可(被写入)。这个value被认定之后,Aceptor与Learner都会接受。最终进程也能Learn(读取到)
Paxos算法流程
初识条件:默认信息不会被篡改,信息真实安全
引理(推导):1. Acceptor要存在多个,(推导:只有一个acceptor -> acceptor 进程阻塞 -> 系统宕机)
2. Acceptor选定它所受到的第一个value (即使只有一个proposer提出了一个value, 该value也必须被选定,无论延时)
3. 如果value为v的提案被选定了,则更高编号的acceptor必须想定相同v值的value(不同的acceptor由于时延/多Proposer等原因 得到了认定了不同的value --> 没有半数以上认可的value --> acceptor需保证value中的认可值v一致)
4. 更高编号的proposer 提出的 value的 v必须与被认可的value 的v值一致 ( acceptor 接受第一个value 的v, 更高编号 acceptor接受相同的v)
5. 对于任意的[value,v]提出,存在一个半数以上的acceptor子集满足两个条件之一:
* 子集中的Acceptor没有接到过编号小于value的请求
* 子集中value接受过的最大提案编号的提案的value 为 v
基于上述引理(推到),我们可以完成如下流程的的设计
阶段一(Prepare):
- Proposer 向半数以上的acceptor 发送一个编号为N的请求
- 如果Acceptor接到请求后,在acceptor本地保存的编号小于acceptor接收到编号N的情况下(否则不响应或响应错误),根据引理5,Acceptor将承诺不再接受编号小于N的提案(这也是为什么要求本地保存编号小于acceptor收到的编号,否则不接受),将本地保存的最大编号更新为N,并给proposer响应。并且,如果存在接受过的最大编号的提案Value, 会一并返回给Proposer , 否则此字段值为空。
阶段二(accept):
- 如果Proposer接收到一半以上的响应,他就会根据相应内容编辑即将发出的提案value与提案编号N。如果接受到的响应中存在acceptor曾接受的提案value, 则选取接收到的编号最大的value作为编辑内容的value, 否则value值将由自己定义
- 当acceptor接收到 Proposer编号为n的请求时,只要acceptor没有对编号大于N的Propose做出响应,就认可该提议
- 当过半的acceptor接受此提案后,Learner将学习(记忆)被选定的value ,并将未同步的数据acceptor的数据同步
拓展:拜占庭将军问题:
问题引入:
11位将军在隔离的情况下去打仗,每一次确定下一步的目标的时候都要11威将军一起进行投票,并根据少数服从多数的原则进行决 定而11位将军投票决定下轮的行动时,5位将军选择了攻打,4位将军选择了撤退,而出现了两名间谍间谍干了一件什么事情呢? 他 告知 5名选择攻打的将军自己决定攻打,而4位决定撤退的将军自己决定撤退如果将军全体攻打和全体撤退都不算最坏情况。坏就 坏在五名将军去攻打了,四名将军撤退了,即使不知道叛徒所采取的行动,这不是必然凉凉了么…这种问题,就叫做拜占庭问题
问题抛出:
在计算机系统中,由于程序存在挂起,系统存在挂机,网路存在延时等情况经常会出现拜占庭问题。准确的定义如下:在一个有n个 节点的的集群中,存在出现q个节点存在发生错误的情况。如果n<=3q, 系统不可能提出一致的意见,因为任意q节点发出的任意消息 都将左右最后的意见
这里为什么是3q呢,请看后文口信型百战挺问题之解 (可以参考https://www.icode9.com/content-4-1010786.html)
问题解法:
Raft算法–Paxos工程化实现
参考(https://www.jianshu.com/p/6d9017289cd5)
引入:
raft是一个共识算法 (consensus algorithm) , 指即使在部分节点故障,网络延时,网咯分割的情况下多个节点依然能对某一事物/提案保持统一的看法。
Raft算法的特点是易理解,并且在性能,可靠向上不输于Paxos
Raft 是Paxos的问题分解,状态简化版本
正文:
一个Raft集群包含的角色: Leader, Follower, Candidate(候选者,当刚开始Leader未选出或Leader宕机时出现的中间态)
Leader: raft 与Paxos不同,在Paxos中由于担心节点的挂起等问题并不存在Learder的概念,毕竟Leader挂起不久凉凉了么,raft会在开始的时候选出一个leader, 并在leader挂起的时候重新选取一个新的leader。
raft中的leader负责节点日志同步(replicated log)管理,并接受所有(follower收到请求之后会重定向给leader)客户端的更新请求(写命令,会全部同步给全部的follower),通过heartBeat连接followers写入更新请求。 **** 如果有Follower因为网络延时或挂起的原因未成功更新,Leader会不断重复尝试附加日志条目**(当Leaders收到大多数follower的恢复后会将这条日志应用道他本身的状态集中,并将执行的结果返回客户端。)尽管已经回复了客户端。** 直到所有的follower更新成功保持强一致性
Follower: 响应Leader的日志同步请求, 响应Candidate的邀票请求
Candidate: 在集群刚启动/Leader宕机的时候由Follower转变而来。当获取票数超过半数时转换为新的leader
流程:
-
A. Leader的选举:
- 阶段一:所有节点都是Follower, 设定一个初识的任期(Term) = 0 ,同时启动选举定时器(每个节点的超市时间不同避免同时发起选举)
- 阶段二:阶段一之后OR Leader宕机**(判断条件,在一个选举定时周期(election timeout)内没有收到heartBeats连接的信息AND没有收到投票请求) 符合条件的Follower转变为Candidate, Term自增**,向所有节点发送投票请求并重置选举定时器
- 阶段三:投票策略。节点收到投票请求后根据Term进行比较,如果Term比自己小(很明显时网络延时),就给子集投票。否则如果自己还没有给其他节点投过票的话就响应并投票给请求人(前提要求:他的日志版本和自己的相等或更新,比较方法:Term+日志长度)
- 阶段四:如果不存在Candidate超过半数半数的票数则进行下一轮的选举,存在Candidate会转化为Leader,并定时发送心跳给其他节点,其他节点也会恢复为follower与Leader保持同步。至此,选举完成
-
B. 日志同步更新 Log Replication
-
阶段一:Leader接收到客户端的请求,将请求最为日志条目(Entry) 写入本地日志。由于此时尚未要求Follower同步,所以leader并未将请求放入本地状态机中运行,也不会更新本地数据
-
阶段二: Leader将Entry(大概率是Entry数组,因为在一次HeartBeat同步周期中有可能出现客户端发起多次请求的状况,所以在心跳同步中将积攒的所有日志目录进行同步)并行的发送给其他的follower(通过HeartBeat附加信息的方法)
此过程中可能出现的问题:
Leader发送Entry时,会追加发送之前条目的索引位置(保证数据一致),Leader的Term(保证Leader与Follower的一致性),因而由于数据丢包,网络延迟现象的存在可能存在节点数据不一致的情况
对于这种情况Follower和Leader回溯索引位置(有指针内味了)找到最后一个相同的日志条目,删除Follower从最后一个开始后面不同步的数据条目,并同步Leader的数据。
-
阶段三: Leader等待Follower的响应:Success OR False. 当收到超过半数的Success回应,Leader就会把此条Entry(也可能是Entry数组) 写入状态机中,并给客户端机型响应。
-
阶段四: 在Leader回应完客户端后,会告知Followers 刚刚的日志已做出响应。对于刚刚False的节点重复请求保证强一致性。
-
-
C. Raft的安全性与数据一致性
为保证followers之间的数据一致,follower对Leader的数据只有读权限,无法进行覆盖更改。且follower无权更改leader的数字。 Leader本身不会主动覆盖数据(除非人为的数据清洗)
-
拓展: HeartBeat
Heartbeat 是一个基于Linux开源的高可用集群系统。主要包括心跳服务和资源接管两个高可用集群组件。心跳监测服务可以 通过网络链路和串口进行,而且支持冗余链路, 它们之间相互发送报文来告诉对方自己当前的状态,如果在指定的时间内未 收到对方发送的报文,那么就认为对方失效,这时需启动资源接管模块来接管运行在对方主机上的资源或者服务。在Raft中并 不一定需要Heartbeat进行Leader和Follower的连接,也可以用RPC(远程控制)进行连接.
HeartBeat具体使用方法可以参考https://blog.youkuaiyun.com/kkdelta/article/details/39780611
Zab协议 – 又一个分布式一致性的好帮手
Zab属于是纯纯的实战了,为了分布式协调服务Zookeeper专门涉及的一种**支持崩溃恢复的原子广播协议。
zab属于几乎是由raft衍生出来的协议了,在zab中同样的,存在两种角色: Leader和Follower.
与raft的不同的是,虽然事物依旧是由Leader来处理,但是对数据的仅仅是读请求则可以由follower来处理
Zab协议的两种模式:
A. 崩溃恢复:Leader崩溃 or 集群刚启动 or 失去了半数机器支持
Leader会重新选举,选举的流程大体跟raft一样
新Leader产生后会与过半的follower进行同步,使数据一致
与raft有略微差别,Leader判断数据谁更新的方法使用Zxid, 虽然类似刚刚的Temp,但是有细微差别。Zxid一共64位。低 32位为单调递增的计数器(就是Temp),高三十二位代表了Leader年代编号(表示担任Leader的不同时期)
与raft不同,zab进行选举时是所有节点同时进行,相互进行各自Zxid的比较,最终将选举结果广播。
广播格式(ServerID(投票者的设备ID), t投票对象的ServerID + Zxid))
B. 消息广播:集群中所有的写请求由leader处理,如follower处理读请求,须先向leader同步数据(sync())
当Leader收到请求后执行请求并转化为事务(Proposal) 并将Proposal广播给Follower。当收到半数以上Follower响应就执 行事务得到Commit信息,并向Follower广播Commit
简单负载均衡策略
- 轮询:将请求按顺序轮流分配到后端服务器上,均衡对待后端每一台服务器,不关心服务器实际连接数与当前系统负载
- 加权轮询:根据服务器得配置,其系统的负载配置权重,给配置高,负载低的机器配置更高权重,处理更多请求。
- 随机: 随机分配。当调用多的时候结果与轮询也越来越近似
- 加权随机: 与加权轮询类似,但是配置请求不考虑请求得先后顺序。
- 源地址HASH: 获取客户得IP地址,用改数值对服务器列表大小取模(HASH链表属于是) ,采用源HASH负载均衡分配请求给服务器。好处是共享session
- 最小连接数:根据后端服务当前的连接情况,动态地选取当前挤压连接数最少的一名服务器处理当前得请求,尽量合理的分配
集群,分布式,SOA, 微服务概念
来简单得回顾一下网络时代得网站设置:
首先是单节点,属于是最初的古早版本。当时有计算机得不多,连ipv4都是一抓一大把的时代。人们根本无需为资源的使用操心
而后来由计算机的发展,带宽的增大,单节点计算机无法圣人,于是就出现了集群。集群是同时对外提供服务,集群中的节点共同分担请求,每个节点都是一个完整的可提供服务对象(nginx可以搞)
当服务太大的时候,我们集群也有点撑不住了,因为服务内部本身也是有模块使用的频率区分。分布式就是将服务分割为不同的模块。这个时候节点不能单独提供整个服务了,就需要协同工作了,也就是我们上面讲到的分布式原理协同。其实集群和分布式的概念相差并不大,不过集群更讲求节点上服务的完整性,而分布式更强调节点之间的协同。
SOA 是在分布式中为了给分布式的模块互相调用交互进行解耦。 他提出了一种ESB的概念, 取消了互相之间的调用,而是将所用功能结合成一根服务总线,服务之间不在互相交互,而是通过ESB来执行。SOA的 概念就是面向服务,而本身采用总线这种有瓶颈的结构,肯定只是昙花一现。而微服务也不负众望的应运而生
微服务还是采用多任务部署的模式,但是与SOA用总线得中心化思想不同,微服务走的是一条去中心化路线。微服务提供注册中心,API网关等等组件,或说本身也是一个服务。侧重服务得单一原则,将球服务单个正常使用。去掉ESB总线,采用restapi进行通讯。
分布式系统的设计目标:
- 可扩展性:通过服务,存储得扩展,提过系统的处理能力
- 高可用性:单点不影响整体,不发生单点故障(一旦系统中某组件失效,系统便无法工作)
- 无状态:满足机器宕机不影响全部服务,可随时进行扩展得要求
- 可管理:便于运维
- 高可靠性:同样的请求返回同样的数据,能够数据持久化且数据不会丢失