参考:
https://zhuanlan.zhihu.com/p/348753812
https://github.com/wangzhiwubigdata/God-Of-BigData#Spark%E5%AE%9E%E6%88%98%E5%90%88%E9%9B%86
**单点故障:**单个点发生故障的时候会波及到整个系统或者网络,从而导致整个系统或者网络的瘫痪
**分布性:**分布式系统中的多台计算机之间在空间位置上可以随意分布,同时,机器的分布情况也会随时变动。
对等性:分布式系统中的计算机没有主/从之分,即没有控制整个系统的主机,也没有被控制的从机,组成分布式系统的所有计算机节点都是对等的。副本(Replica)是分布式系统最常见的概念之一,指的是分布式系统对数据和服务提供的一种冗余方式。在常见的分布式系统中,为了对外提供高可用的服务,我们往往会对数据和服务进行副本处理。数据副本是指在不同节点上持久化同一份数据,当某一个节点上存储的数据丢失时,可以从副本上读取该数据,这是解决分布式系统数据丢失问题最为有效的手段。另一类副本是服务副本,指多个节点提供同样的服务,每个节点都有能力接收来自外部的请求并进行相应的处理。
**并发性:**在一个计算机网络中,程序运行过程的并发性操作是非常常见的行为。例如同一个分布式系统中的多个节点,可能会并发地操作一些共享的资源,如何准确并高效地协调分布式并发操作也成为了分布式系统架构与设计中最大的挑战之一。
**缺乏全局时钟:**在分布式系统中,很难定义两个事件究竟谁先谁后,原因就是因为分布式系统缺乏一个全局的时钟序列控制。
**故障总是会发生:**组成分布式系统的所有计算机,都有可能发生任何形式的故障。除非需求指标允许,在系统设计时不能放过任何异常情况。
CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、**Partition tolerance(分区容错性)**这三个基本需求,最多只能同时满足其中的2个。
什么是分区?
当网络由于发生异常情况,导致分布式系统中部分节点之间的网络延时不断增大,最终导致组成分布式系统的所有节点中,只有部分节点之间能够进行正常通信,而另一些节点则不能——我们将这个现象称为网络分区,就是俗称的**“脑裂”**。当网络分区出现时,分布式系统会出现局部小集群,在极端情况下,这些局部小集群会独立完成原本需要整个分布式才能完成的功能,这就对分布式一致性提出类非常大的挑战。
当N1机器请求数据更新,N1中的数据V0将被更新为V1,如果此时网络断开,分布式系统无法将操作同步到N2机器,所以N2中的数据依旧是V0。这个时候,有用户向N2发送数据读取请求,由于数据还没有进行同步,应用程序没办法立即给用户返回最新的数据V1,怎么办呢?
这里有两种选择:
第一:**牺牲数据一致性,保证可用性。**响应旧的数据V0给用户。
第二:**牺牲可用性,保证数据一致性。**阻塞等待,直到网络连接恢复,数据更新操作M完成之后,再给用户响应最新的数据V1。 这个过程,证明了要满足分区容错性的分布式系统,只能在一致性和可用性两者中,选择其中一个。
CAP原则权衡:
通过CAP理论,我们知道无法同时满足一致性、可用性和分区容错性这三个特性,那要舍弃哪个呢?
BASE是对CAP中一致性和可用性权衡的结果,其核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务特点,才用适当的方式来使系统打到最终一致性。
CAP的3选2伪命题
实际上,不是为了P(分区容错性),必须在C(一致性)和A(可用性)之间任选其一。分区的情况很少出现,CAP在大多时间能够同时满足C和A。
对于分区存在或者探知其影响的情况下,需要提供一种预备策略做出处理:
探知分区的发生; 进入显示的分区模式,限制某些操作; 启动恢复过程,恢复数据一致性,补偿分区发生期间的错误。
BASE理论简介
BASE理论是Basically Available(基本可用),**Soft State(软状态)和Eventually Consistent(最终一致性)**三个短语的缩写。
其核心思想是:
既是无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。
BASE理论的内容
基本可用
假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
**响应时间上的损失:**正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在2秒作用返回结果。
**功能上的损失:**在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单。但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
软状态
相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种“硬状态”。
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。但不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性。
最终一致性
最终一致性分为5种:
分布式事务:
指事务的操作位于不同的节点上,需要保证事务的 AICD 特性。例如在下单场景下,库存和订单如果不在同一个节点上,就需要涉及分布式事务。
分布式锁:
可以使用 Java 提供的内置锁来实现进程同步:由 JVM 实现的 synchronized 和 JDK 提供的 Lock。但是在分布式场景下,需要同步的进程可能位于不同的节点上,那么就需要使用分布式锁来同步。
当两(多)个节点同时认为自已是唯一处于活动状态的服务器从而出现争用资源的情况,这种争用资源的场景即是所谓**的“脑裂”(split-brain)**或”区间集群“(partitioned cluster)。
HeartBeat原理:
HeartBeat运行于备用主机上的,Heartbeat可以通过以太网连接检测主服务器的运行状态,一旦其无法检测到主服务器的"心跳"则自动接管主服务器的资源。通常情况下,主、备服务器间的心跳连接是一个独立的物理连接,这个连接可以是串行线缆、一个由"交叉线"实现的以太网连接。Heartbeat甚至可同时通过多个物理连接检测主服务器的工作状态,而其只要能通过其中一个连接收到主服务器处于活动状态的信息,就会认为主服务器处于正常状态。
分布式系统使用逻辑时钟记录事件顺序关系:
什么是逻辑时钟:
逻辑时钟是为了区分现实中的物理时钟提出来的概念,一般情况下我们提到的时间都是指物理时间,但实际上很多应用中,只要所有机器有相同的时间就够了,这个时间不一定要跟实际时间相同。更进一步,如果两个节点之间不进行交互,那么它们的时间甚至都不需要同步。因此问题的关键点在于节点间的交互要在事件的发生顺序上达成一致,而不是对于时间达成一致。
每个事件对应一个Lamport时间戳,初始值为0,如果事件在节点内发生,时间戳加1;如果事件属于发送事件,时间戳加1并在消息中带上该时间戳;如果事件属于接收事件,时间戳 = Max(本地时间戳,消息中的时间戳) + 1
综上,逻辑时钟指的是分布式系统中用于区分事件的发生顺序的时间机制。从某种意义上讲,现实世界中的物理时间其实是逻辑时钟的特例。
为什么不用物理时钟?
现实生活中物理时间有统一的标准,而分布式系统中每个节点记录的时间并不一样,即使设置了 NTP 时间同步节点间也存在毫秒级别的偏差。因而分布式系统需要有另外的方法记录事件顺序关系,这就是逻辑时钟(logical clock)。
2PC(two phase commit)两阶段提交顾名思义它分成两个阶段,先由一方进行提议(propose)并收集其他节点的反馈(vote),再根据反馈决定提交(commit)或中止(abort)事务。我们将提议的节点称为协调者(coordinator),其他参与决议节点称为参与者(participants, 或cohorts)
3PC(three phase commit)即三阶段提交,在2PC中一个participant的状态只有它自己和coordinator知晓,假如coordinator提议后自身宕机,在watchdog启用前一个participant又宕机,其他participant就会进入既不能回滚、又不能强制commit的阻塞状态,直到participant宕机恢复。这引出两个疑问:
Zookeeper可以理解为一个特殊的高可用性的文件系统,不过这个文件系统没有文件和目录,Zookeeper中数据存储于内存之中,统一使用节点znode,作为保存数据的容器,也可以作为保存其他znode的容器。所有znode构成一个层次化的命名空间。每一个节点可以通过路径来标识。Znode能存储的数据被限制在1MB以内
Znode分为两种类型:
集群
Zookeeper集群中有几个关键的概念,Leader、Follower和Observer,Zookeeper中通常只有Leader节点可以写入,Follower和Observer都只是负责读,但是Follower会参与节点的选举和过半写成功,Observer则不会,他只是单纯的提供读取数据的功能。通常这样设置的话,是为了避免太多的从节点参与过半写的过程,导致影响性能,这样Zookeeper只要使用一个几台机器的小集群就可以实现高性能了,如果要横向扩展的话,只需要增加Observer节点即可。
权限控制ACL :Zookeeper使用ACL来进行权限的控制,每个节点都有其对应的ACL包含以下5种:
Zookeeper通过集群的方式来做到高可用,通过内存数据节点Znode来达到高性能,但是存储的数据量不能太大,通常适用于读多写少的场景。
他有几个特性:
主要流程如下:
ZAB协议详解
Zookeeper通过ZAB原子广播协议(ZooKeeper Atomic Broadcast )来实现数据的最终顺序一致性,他是一个类似2PC两阶段提交的过程。ZAB协议定义了选举(election)、发现(discovery)、同步(sync)、广播(Broadcast)四个阶段
由于Zookeeper 只有Leader节点可以写入数据,如果是其他节点收到写入数据的请求,则会将之转发给Leader节点。
主要流程如下:
Leader的选举可以分为两个方面,同时选举主要包含事务zxid和myid,节点主要包含LEADING\FOLLOWING\LOOKING3个状态。
选举之后又是怎样进行数据同步的?
那实际上Zookeeper在选举之后,Follower和Observer(统称为Learner)就会去向Leader注册,然后就会开始数据同步的过程。
数据同步包含3个主要值和4种形式。
直接差异化同步 DIFF同步
如果PeerLastZxid在minCommittedLog和maxCommittedLog之间,那么则说明Learner服务器还没有完全同步最新的数据。
这个设置针对的是一个异常的场景。
如果Leader刚生成一个proposal,还没有来得及发送出去,此时Leader宕机,重新选举之后作为Follower,但是新的Leader没有这个proposal数据。
假设现在的Leader是A,minCommittedLog=1,maxCommittedLog=3,刚好生成的一个proposal的ZXID=4,然后挂了。重新选举出来的Leader是B,B之后又处理了2个提议,然后minCommittedLog=1,maxCommittedLog=5。这时候A的PeerLastZxid=4,在(1,5)之间。那么这一条只存在于A的提议怎么处理?A要进行事务回滚,相当于抛弃这条数据,并且回滚到最接近于PeerLastZxid的事务,对于A来说,也就是PeerLastZxid=3。流程和DIFF一致,只是会先发送一个TRUNC命令,然后再执行差异化DIFF同步。
仅回滚同步 TRUNC同步
针对PeerLastZxid大于maxCommittedLog的场景,流程和上述一致,事务将会被回滚到maxCommittedLog的记录。这个其实就更简单了,也就是你可以认为TRUNC+DIFF中的例子,新的Leader B没有处理提议,所以B中minCommittedLog=1,maxCommittedLog=3。所以A的PeerLastZxid=4就会大于maxCommittedLog了,也就是A只需要回滚就行了,不需要执行差异化同步DIFF了。
全量同步 SNAP同步
适用于两个场景:
数据不一致问题还是会存在的,可以分成3个场景来描述这个问题:
1. 查询不一致
因为Zookeeper是过半成功即代表成功,假设我们有5个节点,如果123节点写入成功,如果这时候请求访问到4或者5节点,那么有可能读取不到数据,因为可能数据还没有同步到4、5节点中,也可以认为这算是数据不一致的问题。
解决方案可以在读取前使用sync命令。
2. leader未发送proposal宕机
这也就是数据同步说过的问题。
leader刚生成一个proposal,还没有来得及发送出去,此时leader宕机,重新选举之后作为follower,但是新的leader没有这个proposal。这种场景下的日志将会被丢弃。
3. leader发送proposal成功,发送commit前宕机
如果发送proposal成功了,但是在将要发送commit命令前宕机了,如果重新进行选举,还是会选择zxid最大的节点作为leader,因此,这个日志并不会被丢弃,会在选举出leader之后重新同步到其他节点当中。