带你快速了解分布式协调框架ZooKeeper

一、初识ZooKeeper

ZooKeeper最早起源于雅虎,雅虎很多大型服务器都需要一个类似的分布式协调系统来进行工作,但是这些系统往往存在着单点问题(单点问题指系统某一服务失效会导致整个系统处于不可用的状态),所以这些雅虎的技术大牛们就尝试去开发一款专门的分布式协调系统,提供一些基本的API,让开发人员能够将精力放在业务逻辑的开发上而不要考虑各种分布式协调问题。

如今ZooKeeper已成为Apache软件基金会的一个软件项目,它曾经是著名的分布式计算框架Hadoop的一个子项目,但如今是一个独立的顶级项目。

二、ZooKeeper入门

可以把ZooKeeper看成一个特殊的分布式存储系统,它提供一种类似于Linux文件系统的数据结构(图片来自网络):
在这里插入图片描述
看上去是不是很像Linux系统的目录结构?用 / 表示根节点,然后可以创建很多个子节点。在ZooKeeper中,节点称之为数据节点(ZNode),ZNode不像Linux文件系统那样有文件夹和文件之分,每个ZNode都可以存入数据(不超过1MB),也可以建立很多子节点。

下面我们来讲解ZNode

2.1 数据节点——ZNode

ZooKeeper中,ZNode可以分为持久节点临时节点。客户端在创建持久节点后,除非主动进行删除操作,否则这个节点会一直保留在ZooKeeper服务器中。而对于临时节点就不一样了,它的生命周期和客户端会话绑定,当客户端连接到ZooKeeper服务器并主动创建临时节点后,只要客户端断开了连接并且会话失效,那么这个ZNode也随之会删除。

此外,ZNode的节点还可以细分为2种:Sequential节点和非Sequential节点,Sequential节点在创建后节点名称会自动加上一个递增的整型数字。例如客户端调用API创建一个Sequential的持久节点"/test"后,其节点实际名称为"/test0000000001"

2.2 集群角色

了解数据节点ZNode后,我们来了解一下ZooKeeper集群的角色。
ZooKeeper集群有三种角色:LeaderFollowerObserver,每个ZooKeeper服务器在启动时需要绑定三个端口:用于客户端连接的端口、用于选举Leader的端口、ZooKeeper服务器集群通信端口。
在这里插入图片描述
(图片来自网络)
ZooKeeper集群当中的所有服务器都是通过一个Leader选举过程来选定一台称之为Leader的服务器,Leader服务器为客户端提供读服务、写服务(读和写指的是对ZNode的操作)。
除了Leader以外,FollowerObserver能够提供读服务(不提供写服务,客户端发起的写服务转交给Leader处理)。FollowerObserver唯一的区别在于,Observer不参与Leader的选举,也不会参与写操作的“过半写成功”策略。

2.3 会话

这里的会话指的是客户端与ZooKeeper服务器建立的会话。客户端与ZooKeeper的连接方式为TCP长连接,在客户端与ZooKeeper建立起TCP连接后,其会话的生命周期便开始了。在这个TCP长连接中,客户端可通过心跳检测来保证与服务器的有效会话,能够向ZooKeeper发起各种请求,同时ZooKeeper也可以向客户端发送事件通知(前提是客户端向ZooKeeper注册了事件监听器Watcher)。

2.4 事件监听器——Watcher

事件监听器是ZooKeeper的一个非常重要的特性,很多分布式协调工作离开不了它。它实现了ZooKeeper的一对多的订阅发布模式,能够让多个订阅者(客户端)同时监听某个对象,当这个被监听的对象状态发生变化时,ZooKeeper服务器会主动通知订阅者,然后根据订阅者实现的逻辑处理这个事件。
例如:客户端可以在ZNode节点注册一些Watcher,当有特定事件(例如ZNode的删除、添加、数据的变更等)触发时,ZooKeeper服务器会主动根据Watcher向客户端发起通知。

Watcher机制是ZooKeeper实现分布式协调服务的十分重要的特性,这个机制让基于ZooKeeper实现的分布式应用得到了解耦,这些应用只需要对ZooKeeper服务器进行操作,而无需关注各种分布式的协调问题。

总结

1、ZooKeeper本身就是一个为分布式而生的程序,只要有半数以上的ZooKeeper服务器存活,ZooKeeper服务就能正常使用。
2、ZooKeeper将数据保存在内存中,保证了它的高吞吐量和低延迟特性,这也是为什么ZooKeeper要限制ZNode最大大小为1MB。
3、ZooKeeper在读操作大于写操作的情况下是高性能的,因为写操作会导致所有ZooKeeper服务器的同步。
4、对于分布式理论CAP,ZooKeeper保证了CP(一致性和分区容错性),舍弃了A(可用性)。
5、ZooKeeper实际上只有2个功能:负责管理客户端提交的数据、为客户端提供ZNode的监听服务。

三、ZAB协议

3.1 简介

ZAB协议是ZooKeeper的核心,ZooKeeper通过ZAB协议,实现了数据的强一致性(即实现了CAP理论中的CP),它面向ZooKeeper提出了四个需求:
(1)可靠的提交:一个消息一旦被一个节点提交,它一定最终被所有服务提交
(2)全局顺序:如果在一个节点上,一个消息A在消息B之前被提交,那么对于其它所有节点,一定也是消息A在消息B之前提交。
(3)因果顺序:如果消息B依赖于消息A,那么消息A的提交必须在消息B之前
(4)前序性:如果一个消息被提交,那么这个消息之前提出的所有消息都应该被提交。

基于上述需求,ZooKeeper实现了一种主备模式的系统架构来保持集群中各节点的数据一致性,其基本思路是:
所有来自客户端的事务的请求都必须由Leader服务器处理,Leader服务器负责将客户端的事务请求转换为一个事务提议Proposal),并将这个事务提议分发给Follower服务器。之后,Leader服务器便等待Follower服务器的响应,一旦有超过半数的Follower服务器给出了正确的反馈后,那么Leader就会向所有的Follower分发事务提交消息。

简单介绍了ZAB协议后,我们来了解一下ZAB协议的两种基本模式:消息广播和崩溃恢复
在这里插入图片描述

3.2 消息广播

消息广播分为了4个步骤:
(1)Leader服务器接收到来自客户端的请求后,按照其接受到请求的顺序,给请求分配一个ZXID(每个请求唯一),随后Leader服务器会将请求转发给Follower,同时按照发送顺序写入本地日志。
(2)Follower收到来自LeaderProposal消息后,那么将按照消息收到的顺序写入本地日志持久化,持久化完成后向Leader服务器发送ACK消息。
(3)对于一个请求,如果Leader收到了超过半数的Follower的ACK消息,那么Leader服务器就会提交这个事务,并随后发送Commit消息给各个Follower
(4)Follower收到Commit消息后,提交对应的请求。

我们以一个客户端连接Follower服务器并向Follower服务器发起ZNode写请求来分析这一过程:
在这里插入图片描述

在ZAB协议的事务编号ZXID设计中,ZXID是一个64位的整型数字,其中低32位可以看成是一个递增的计数器(类似AtomicInteger),每当Leader产生一个事务后,就会从对该数字进行一个加1操作。高32位则表示Leader周期,称之为epoch,当老Leader崩溃后重新选举了一个新的Leader服务器的时候,就会从新Leader上取出其本地日志中最大ZXID的事务,并从该ZXID中取出其epoch值并对其进行加1操作,之后就以这个数字作为新的epoch,然后将低32位重置为0。

3.3 崩溃恢复

Leader服务器处于刚启动的状态、出现故障、或者网络连接发生异常导致失去与过半的Follower服务器的联系时,那么就会进入崩溃恢复模式。崩溃恢复模式的目的是选举出一个新的Leader服务器,因此ZAB协议需要的是一个高效且可靠的Leader选举算法,确保能够快速选出Leader服务器。

崩溃恢复需要满足以下两个需求:
1、已经被处理的消息不能被丢弃。
2、没有被处理的消息不能再出现。

根据上述需求,ZAB协议将崩溃恢复过程划分了两个阶段:
1、Leader选举阶段: 当检测到Leader发生崩溃或者网络连接超时后,选举出一个新的Leader
(1)FollowerLeader候选者(准Leader)发送包含自己最后接收到的事务的epoch值的消息,该消息称之为Cepoch消息。
(2)Leader候选者接收到过半的Follower发出的Cepoch消息后,设置自己的epoch为所有Cepoch消息中最大的值加1。随后,准Leader会发送Newepoch消息(内容包含新的epoch值)给这些过半的Follower
(3)Follower收到Newepoch消息后,如果本地的epoch值小于消息中的epoch值,那么就更新本地的epoch值为消息中的值,这样Follower就不能再接受之前epochLeader消息。接着向Leader候选者发送Ack-E消息,这个消息包含了原先的epoch值和该Follower的本地日志(内容包含它处理过的历史事务)
(4)当Leader候选者收到Ack-E消息后,从中选择一个Follower的日志文件作为本地日志,优先选择epoch最大的日志,如果epoch相同,则选择ZXID最大的日志。此时Leader候选者正式成为了Leader服务器,但是需要经历同步阶段才能接受新的客户端请求。

ZAB协议并没有直接规定如何选择一个节点作为未来的Leader候选人,在ZooKeeper的实现中采取了以下规则:选择了多数派中ZXID最大的节点作为Leader候选人,这样可以让新的Leader日志文件包含了最多的被提交的请求,简化了同步阶段的流程,减少FollowerLeader发生日志的消息开销。

2、同步阶段:新的Leader服务器和多数Follower的日志保持一致。
(1)Leader服务器以消息的形式发送整个日志和本地epoch给所有的Follower,这个消息称之为Newleader
(2)Follower收到Newleader消息后,如果发现本地的epoch和消息中的epoch相同,那么会回复ACK给Leader服务器。
(3)Leader收到了超过一半的Follower服务器的ACK后,就发送Commit消息给Follower,此时,Leader服务器开始正式接受来自客户端的请求。
(4)Follower收到Commit消息后提交本地日志中的所有内容。

四、典型应用场景

ZooKeeper能够很好地保证分布式环境中数据的一致性,基于这种特性ZooKeeper成为了解决分布式一致性问题的利器。

4.1 配置中心

配置中心顾名思义就是将负责存储配置数据并将配置提供给其它的应用。
配置信息有以下3个特性:
1、数据量比较小
2、数据内容运行时可能会发生变化
3、需要各个服务器共享

针对上述特性,可以将一些应用程序的配置信息存储在ZNode中。在客户端程序初始化阶段需要配置信息的时候,可以直接通过获取ZNode上的信息来拿到配置完成初始化。
如果客户端还需要关注配置信息的变化,可以通过注册一个WatcherZooKeeper服务器,当配置发生变化时,ZooKeeper会根据Watcher主动通知客户端,客户端只需要通过API重新获取ZNode的内容即可。

4.2 分布式协调/通知

对于一个在多台服务器上部署的应用程序而言,通常需要一个协调者来控制整个系统的运转。在应用程序中通过使用ZooKeeper进行协调,可以很好地减少系统之间的耦合性,而且能够显著系统的可扩展性。

ZooKeeper中的Watcher机制能够实现分布式环境下不同的服务器之间的协调与通知。应用程序通过连接ZooKeeper服务器将一些Watcher进行注册,监听ZNode的变化,ZNode在发生变化后,客户端能够及时收到Watcher通知并做出相应的处理。

4.3 集群管理

集群管理包含两个部分:集群控制和集群监控。
在基于分布式的应用程序运行期间,我们常常有以下需求:
1、需要获知集群有多少服务器正在工作
2、监控服务器或者应用程序的状态

对于需求一,我们可以通过API创建一个临时的ZNode,比如创建一个/server/10.0.0.1节点,那么我只需要知道/server下有多少个ZNode,就可以知道有多少台服务器正在工作。

对于需求二,我们同样可以创建一个ZNode,并将服务器状态写入ZNode中,监控中心只需要注册一个Watcher并关注这些节点的变化,然后将状态记录下来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值