ZooKeeper总结——了解级别

Posted Icedzzz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZooKeeper总结——了解级别相关的知识,希望对你有一定的参考价值。

参考:
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

1. 分布式理论

  1. 集中式与分布式
  • 集中式系统:所谓的集中式系统就是指由一台或多台主计算机组成中心节点,数据集中存储于这个中心节点中,并且整个系统的所有业务单元都集中部署在这个中心节点上,系统的所有功能均由其集中处理。
  • 分布式系统 :是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。分布式意味着可以采用更多的普通计算机(相对于昂贵的大型机)组成分布式集群对外提供服务。

**单点故障:**单个点发生故障的时候会波及到整个系统或者网络,从而导致整个系统或者网络的瘫痪

  1. 分布式系统特点
  • **分布性:**分布式系统中的多台计算机之间在空间位置上可以随意分布,同时,机器的分布情况也会随时变动。

  • 对等性:分布式系统中的计算机没有主/从之分,即没有控制整个系统的主机,也没有被控制的从机,组成分布式系统的所有计算机节点都是对等的。副本(Replica)是分布式系统最常见的概念之一,指的是分布式系统对数据和服务提供的一种冗余方式。在常见的分布式系统中,为了对外提供高可用的服务,我们往往会对数据和服务进行副本处理。数据副本是指在不同节点上持久化同一份数据,当某一个节点上存储的数据丢失时,可以从副本上读取该数据,这是解决分布式系统数据丢失问题最为有效的手段。另一类副本是服务副本,指多个节点提供同样的服务,每个节点都有能力接收来自外部的请求并进行相应的处理。

  • **并发性:**在一个计算机网络中,程序运行过程的并发性操作是非常常见的行为。例如同一个分布式系统中的多个节点,可能会并发地操作一些共享的资源,如何准确并高效地协调分布式并发操作也成为了分布式系统架构与设计中最大的挑战之一。

  • **缺乏全局时钟:**在分布式系统中,很难定义两个事件究竟谁先谁后,原因就是因为分布式系统缺乏一个全局的时钟序列控制。

  • **故障总是会发生:**组成分布式系统的所有计算机,都有可能发生任何形式的故障。除非需求指标允许,在系统设计时不能放过任何异常情况。

CAP理论

CAP定理,指的是在一个分布式系统中,Consistency(一致性)Availability(可用性)、**Partition tolerance(分区容错性)**这三个基本需求,最多只能同时满足其中的2个。

  1. Consistency(一致性) 指数据在多个副本之间能够保持一致的特性(严格的一致性)
  2. Availability(可用性) 这个指的是对于每一个请求,节点总是可以在合理的时间返回合理的响应(不保证获取的数据为最新数据)
  3. Partition tolerance(分区容错性) 分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障

什么是分区?
当网络由于发生异常情况,导致分布式系统中部分节点之间的网络延时不断增大,最终导致组成分布式系统的所有节点中,只有部分节点之间能够进行正常通信,而另一些节点则不能——我们将这个现象称为网络分区,就是俗称的**“脑裂”**。当网络分区出现时,分布式系统会出现局部小集群,在极端情况下,这些局部小集群会独立完成原本需要整个分布式才能完成的功能,这就对分布式一致性提出类非常大的挑战。

当N1机器请求数据更新,N1中的数据V0将被更新为V1,如果此时网络断开,分布式系统无法将操作同步到N2机器,所以N2中的数据依旧是V0。这个时候,有用户向N2发送数据读取请求,由于数据还没有进行同步,应用程序没办法立即给用户返回最新的数据V1,怎么办呢?
这里有两种选择:
第一:**牺牲数据一致性,保证可用性。**响应旧的数据V0给用户。
第二:**牺牲可用性,保证数据一致性。**阻塞等待,直到网络连接恢复,数据更新操作M完成之后,再给用户响应最新的数据V1。 这个过程,证明了要满足分区容错性的分布式系统,只能在一致性和可用性两者中,选择其中一个。

CAP原则权衡:
通过CAP理论,我们知道无法同时满足一致性、可用性和分区容错性这三个特性,那要舍弃哪个呢?

  1. CA without P 如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但其实分区不是你想不想的问题,而是始终会存在,因此CA的系统更多的是允许分区后各子系统依然保持CA。
  2. CP without A 如果不要求A(可用),相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
  3. **AP wihtout C 要高可用并允许分区,则需放弃一致性。**一旦分区发生,节点之间可能会失去联系,为了高可用,**每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。**现在众多的NoSQL都属于此类。

BASE理论

BASE是对CAP中一致性和可用性权衡的结果,其核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务特点,才用适当的方式来使系统打到最终一致性。

  1. CAP的3选2伪命题
    实际上,不是为了P(分区容错性),必须在C(一致性)和A(可用性)之间任选其一。分区的情况很少出现,CAP在大多时间能够同时满足C和A。
    对于分区存在或者探知其影响的情况下,需要提供一种预备策略做出处理:
    探知分区的发生; 进入显示的分区模式,限制某些操作; 启动恢复过程,恢复数据一致性,补偿分区发生期间的错误。

  2. BASE理论简介
    BASE理论是Basically Available(基本可用),**Soft State(软状态)Eventually Consistent(最终一致性)**三个短语的缩写。
    其核心思想是:
    既是无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

  3. BASE理论的内容

  4. 基本可用
    假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
    **响应时间上的损失:**正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在2秒作用返回结果。
    **功能上的损失:**在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单。但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。

  5. 软状态
    相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种“硬状态”
    软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。但不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性

  6. 最终一致性
    最终一致性分为5种:

  • **因果一致性(Causal consistency)**指的是:如果节点A在更新完某个数据后通知了节点B,那么节点B之后对该数据的访问和修改都是基于A更新后的值。于此同时,和节点A无因果关系的节点C的数据访问则没有这样的限制。
  • 读己之所写(Read your writes):节点A更新一个数据后,它自身总是能访问到自身更新过的最新值,而不会看到旧值。其实也算一种因果一致性。
  • **会话一致性(Session consistency)**将对系统数据的访问过程框定在了一个会话当中:系统能保证在同一个有效的会话中实现 “读己之所写” 的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。
  • **单调读一致性(Monotonic read consistency)**指的是:如果一个节点从系统中读取出一个数据项的某个值后,那么系统对于该节点后续的任何数据访问都不应该返回更旧的值。
  • **单调写一致性(Monotonic write consistency)**指的是:一个系统要能够保证来自同一个节点的写操作被顺序的执行。

分布式相关问题

分布式事务:
指事务的操作位于不同的节点上,需要保证事务的 AICD 特性。例如在下单场景下,库存和订单如果不在同一个节点上,就需要涉及分布式事务。

分布式锁:
可以使用 Java 提供的内置锁来实现进程同步:由 JVM 实现的 synchronized 和 JDK 提供的 Lock。但是在分布式场景下,需要同步的进程可能位于不同的节点上,那么就需要使用分布式锁来同步

高可用之“脑裂”

当两(多)个节点同时认为自已是唯一处于活动状态的服务器从而出现争用资源的情况,这种争用资源的场景即是所谓**的“脑裂”(split-brain)**或”区间集群“(partitioned cluster)。

HeartBeat原理:

HeartBeat运行于备用主机上的,Heartbeat可以通过以太网连接检测主服务器的运行状态,一旦其无法检测到主服务器的"心跳"则自动接管主服务器的资源。通常情况下,主、备服务器间的心跳连接是一个独立的物理连接,这个连接可以是串行线缆、一个由"交叉线"实现的以太网连接。Heartbeat甚至可同时通过多个物理连接检测主服务器的工作状态,而其只要能通过其中一个连接收到主服务器处于活动状态的信息,就会认为主服务器处于正常状态。

时间、时钟和事件顺序

分布式系统使用逻辑时钟记录事件顺序关系:
什么是逻辑时钟:
逻辑时钟是为了区分现实中的物理时钟提出来的概念,一般情况下我们提到的时间都是指物理时间,但实际上很多应用中,只要所有机器有相同的时间就够了,这个时间不一定要跟实际时间相同。更进一步,如果两个节点之间不进行交互,那么它们的时间甚至都不需要同步。因此问题的关键点在于节点间的交互要在事件的发生顺序上达成一致,而不是对于时间达成一致。
每个事件对应一个
Lamport时间戳
,初始值为0,如果事件在节点内发生,时间戳加1如果事件属于发送事件,时间戳加1并在消息中带上该时间戳如果事件属于接收事件,时间戳 = Max(本地时间戳,消息中的时间戳) + 1

综上,逻辑时钟指的是分布式系统中用于区分事件的发生顺序的时间机制。从某种意义上讲,现实世界中的物理时间其实是逻辑时钟的特例。
为什么不用物理时钟?
现实生活中物理时间有统一的标准,而分布式系统中每个节点记录的时间并不一样,即使设置了 NTP 时间同步节点间也存在毫秒级别的偏差。因而分布式系统需要有另外的方法记录事件顺序关系,这就是逻辑时钟(logical clock)。

2PC和3PC

2PC(two phase commit)两阶段提交顾名思义它分成两个阶段,先由一方进行提议(propose)并收集其他节点的反馈(vote),再根据反馈决定提交(commit)或中止(abort)事务。我们将提议的节点称为协调者(coordinator),其他参与决议节点称为参与者(participants, 或cohorts)

  • 在阶段1中,coordinator发起一个提议,分别问询各participant是否接受。
  • 在阶段2中,coordinator根据participant的反馈,提交或中止事务,如果participant全部同意则提交,只要有一个participant不同意就中止。

3PC(three phase commit)即三阶段提交,在2PC中一个participant的状态只有它自己和coordinator知晓,假如coordinator提议后自身宕机,在watchdog启用前一个participant又宕机,其他participant就会进入既不能回滚、又不能强制commit的阻塞状态,直到participant宕机恢复。这引出两个疑问:

  • 能不能去掉阻塞,使系统可以在commit/abort前回滚(rollback)到决议发起前的初始状态
  • 当次决议中,participant间能不能相互知道对方的状态,又或者participant间根本不依赖对方的状态
    相比2PC,3PC增加了一个准备提交(prepare to commit)阶段来解决以上问题:

    coordinator接收完participant的反馈(vote)之后,进入阶段2,给各个participant发送准备提交(prepare to commit)指令。participant接到准备提交指令后
    可以锁资源,但要求相关操作必须可回滚
    。coordinator接收完确认(ACK)后进入阶段3、进行commit/abort,3PC的阶段3与2PC的阶段2无异。协调者备份(coordinator watchdog)、状态记录(logging)同样应用在3PC。

2.Zookeeper

Zookeeper基础概念

  1. 概念
    Zookeeper 是一个开源的分布式协调服务。Zookeeper 可以用于实现分布式系统中常见的统一配置管理、统一命名服务、集群管理、Master 选举、分布式锁和分布式队列等功能。它具有以下特性:
  • **顺序一致性:**从一个客户端发起的事务请求,最终都会严格按照其发起顺序被应用到 Zookeeper 中;
  • **原子性:**所有事务请求的处理结果在整个集群中所有机器上都是一致的;不存在部分机器应用了该事务,而另一部分没有应用的情况;
  • **单一视图:**所有客户端看到的服务端数据模型都是一致的;
  • **可靠性:**一旦服务端成功应用了一个事务,则其引起的改变会一直保留,直到被另外一个事务所更改;
  • **实时性:**一旦一个事务被成功应用后,Zookeeper 可以保证客户端立即可以读取到这个事务变更后的最新状态的数据。
  1. 数据模型

Zookeeper可以理解为一个特殊的高可用性的文件系统,不过这个文件系统没有文件和目录,Zookeeper中数据存储于内存之中,统一使用节点znode,作为保存数据的容器,也可以作为保存其他znode的容器。所有znode构成一个层次化的命名空间。每一个节点可以通过路径来标识。Znode能存储的数据被限制在1MB以内

Znode分为两种类型:

  • 短暂/临时(Ephemeral):当客户端和服务端断开连接后,所创建的Znode(节点)会自动删除
  • 持久(Persistent):当客户端和服务端断开连接后,所创建的Znode(节点)不会删除

集群
Zookeeper集群中有几个关键的概念,Leader、Follower和Observer,Zookeeper中通常只有Leader节点可以写入Follower和Observer都只是负责读,但是Follower会参与节点的选举和过半写成功,Observer则不会,他只是单纯的提供读取数据的功能。通常这样设置的话,是为了避免太多的从节点参与过半写的过程,导致影响性能,这样Zookeeper只要使用一个几台机器的小集群就可以实现高性能了,如果要横向扩展的话,只需要增加Observer节点即可。

权限控制ACL :Zookeeper使用ACL来进行权限的控制,每个节点都有其对应的ACL包含以下5种:

  • CREATE,创建子节点权限
  • DELETE,删除子节点权限
  • READ,获取节点数据和子节点列表权限
  • WRITE,更新节点权限
  • ADMIN,设置节点ACL权限

Zookeeper通过集群的方式来做到高可用,通过内存数据节点Znode来达到高性能,但是存储的数据量不能太大,通常适用于读多写少的场景

  1. Wather监听机制
    Zookeeper可以提供分布式数据的发布/订阅功能,依赖的就是Wather监听机制。
    客户端可以向服务端注册Wather监听,服务端的指定事件触发之后,就会向客户端发送一个事件通知。

他有几个特性:

  • 一次性:一旦一个Wather触发之后,Zookeeper就会将它从存储中移除
  • 客户端串行:客户端的Wather回调处理是串行同步的过程,不要因为一个Wather的逻辑阻塞整个客户端
  • 轻量:Wather通知的单位是**WathedEvent,只包含通知状态、事件类型和节点路径,不包含具体的事件内容,**具体的时间内容需要客户端主动去重新获取数据

主要流程如下:

  • 客户端向服务端注册Wather监听
  • 保存Wather对象到客户端本地的WatherManager中
  • 服务端Wather事件触发后,客户端收到服务端通知,从WatherManager中取出对应Wather对象执行回调逻辑

Zookeeper是如何保证数据一致性的?

ZAB协议详解
Zookeeper通过ZAB原子广播协议(ZooKeeper Atomic Broadcast )来实现数据的最终顺序一致性,他是一个类似2PC两阶段提交的过程。ZAB协议定义了选举(election)、发现(discovery)、同步(sync)、广播(Broadcast)四个阶段
由于Zookeeper 只有Leader节点可以写入数据,如果是其他节点收到写入数据的请求,则会将之转发给Leader节点。
主要流程如下:

  1. Leader收到请求之后,将它转换为一个proposal提议,并且为每个提议分配一个全局唯一递增的事ID:zxid,然后把提议放入到一个FIFO的队列中,按照FIFO的策略发送给所有的Follower
  2. Follower收到提议之后,以事务日志的形式写入到本地磁盘中,写入成功后返回ACK给Leader
  3. Leader在收到超过半数的Follower的ACK之后,即可认为数据写入成功,就会发送commit命令给Follower告诉他们可以提交proposal了

Zookeeper如何进行Leader选举的

Leader的选举可以分为两个方面,同时选举主要包含事务zxid和myid,节点主要包含LEADING\\FOLLOWING\\LOOKING3个状态

  1. 服务启动期间的选举
  • 首先,每个节点都会对自己进行投票,然后把投票信息广播给集群中的其他节点
  • 节点接收到其他节点的投票信息,然后和自己的投票进行比较,首先zxid较大的优先,如果zxid相同那么则会去选择myid更大者,此时大家都是LOOKING的状态
  • 投票完成之后,开始统计投票信息,如果集群中过半的机器都选择了某个节点机器作为leader,那么选举结束
  • 最后,更新各个节点的状态,leader改为LEADING状态follower改为FOLLOWING状态
  1. 服务运行期间的选举
    如果开始选举出来的leader节点宕机了,那么运行期间就会重新进行leader的选举。
  • leader宕机之后,非observer节点都会把自己的状态修改为LOOKING状态,然后重新进入选举流程
  • 生成投票信息(myid,zxid),同样,第一轮的投票大家都会把票投给自己,然后把投票信息广播出去
  • 接下来的流程和上面的选举是一样的,都会优先以zxid,然后选择myid,最后统计投票信息,修改节点状态,选举结束

选举之后又是怎样进行数据同步的?

那实际上Zookeeper在选举之后,Follower和Observer(统称为Learner)就会去向Leader注册,然后就会开始数据同步的过程。
数据同步包含3个主要值和4种形式。

  • PeerLastZxid:Learner服务器最后处理的ZXID
  • minCommittedLog:Leader提议缓存队列中最小ZXID
  • maxCommittedLog:Leader提议缓存队列中最大ZXID

直接差异化同步 DIFF同步

如果PeerLastZxid在minCommittedLog和maxCommittedLog之间,那么则说明Learner服务器还没有完全同步最新的数据。

  • 首先Leader向Learner发送DIFF指令,代表开始差异化同步,然后把差异数据(从PeerLastZxid到maxCommittedLog之间的数据)提议proposal发送给Learner
  • 发送完成之后发送一个NEWLEADER命令给Learner,同时Learner返回ACK表示已经完成了同步
  • 接着等待集群中过半的Learner响应了ACK之后,就发送一个UPTODATE命令,Learner返回ACK,同步流程结束


先回滚再差异化同步 TRUNC+DIFF同步

这个设置针对的是一个异常的场景。

如果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同步
适用于两个场景:

  • PeerLastZxid小于minCommittedLog
  • Leader服务器上没有提议缓存队列,并且PeerLastZxid不等于Leader的最大ZXID
    这两种场景下,Leader将会发送SNAP命令,把全量的数据都发送给Learner进行同步。

数据不一致问题

数据不一致问题还是会存在的,可以分成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之后重新同步到其他节点当中。

以上是关于ZooKeeper总结——了解级别的主要内容,如果未能解决你的问题,请参考以下文章

Logging模块总结 2018/5/30

隔离级别小总结

隔离级别小总结

一文了解Zookeeper

了解OutOfMemoryError异常 - 深入Java虚拟机读后总结

ZooKeeper核心原理及应用场景