
本文共 7837 字,大约阅读时间需要 26 分钟。
文章目录
一、简介
Zookeeper官网地址:
Zookeeper官网文档地址:
Zookeeper是Google的Chubby一个开源的实现,是Hadoop的分布式协调服务,可用于服务发现、分布式锁、分布式领导选举、配置管理等。而这些,都是建立在Zookeeper提供了类似于Linux文件系统的目录树结构(可以理解为是轻量级的内存文件系统,但只适合存少量信息,完全不适合存储大量文件或者大文件),同时提供了对于每个节点的监控与通知机制。
二、CAP定理
CAP定理,指的是在一个分布式系统中,Consistency(一致性)、Availability(可用性)和Partition tolerance(分区容错性)。
- ①C:Consistency,一致性,数据一致更新,所有数据变动都是同步的。
- ②A:Availability,可用性,系统具有好的响应性能。
- ③P:Partition tolerance,分区容错性。
在一个分布式系统中,一致性、可用性、分区容错性三者不可兼得。在最终一致性上,任何时刻对ZooKeeper的访问请求能得到一致的数据结果。zk使用消息队列来保证指令能够传达到所有的follower,leader把指令放在消息队列中,然后向每个节点发送。消息队列有个特点:不会因为节点延迟、网络中断而导致队列中的消息丢失,直到follower把队列中的消息都“消化”完全了才行。
在可用性方面,在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果。
在分区容错性方面,在遇到任务网络分区故障的时候,仍然能够保证对外提供满足一致性和可用性的服务。除非整个网络环境都发生了故障。ZooKeeper保证了分区容错性,集群中单个服务器发生故障时,只要集群中超过半数的机器还能够正常工作,整个集群就能够对外提供服务。
三、Zookeeper的特性
当然,《Hadoop权威指南》上对Hadoop的特点也有描述:
- Zookeeper是简单的。Zookeeper的核心是一个精简的文件系统,它提供一些简单的操作和一些额外的抽象操作,例如,排序和通知。
- Zookeeper是富有表现力的。Zookeeper的基本操作是一组丰富的“构件”(building block),可用于实现多种协调数据结构和协议。相关的例子包括:分布式队列、分布式锁和一组节点中的“领导者选举”(leader election)。
- Zookeeper具有高可用性。Zookeeper运行于一组机器之上,并且在设计上具有高可用性,因此应用程序完全可以依赖于它。Zookeeper可以帮助系统避免出现单点故障,因此可以用于构件一个可靠的应用程序。
- Zookeeper采用松耦合交互方法。在Zookeeper支持的交互过程中,参与者不需要彼此了解。例如:Zookeeper可以被用于实现“数据汇集”(rendezvous)机制,让进程在不了解其他进程(或网络状况)的情况下,能够彼此发现并进行信息交互。参与的各方甚至可以不必同时存在,因为一个进程可以在Zookeeper中留下一条消息,在该进程结束后,另外一个进程还可以读取这条消息。
- Zookeeper是一个资源库。Zookeeper提供了一个通用协调模式实现方法的开源共享库,使程序员免于写这类通用的协议(这通常是很难写正确的)。所有人都能够对这个资源库进行添加和改进,久而久之,会使每个人都从中受益。 同时,Zookeeper也是高性能的。在它的诞生地Yahoo!公司,对于以写操作为主的工作负载来说,Zookeeper的基准吞吐量已经超过每秒10000个操作。对于常规的以读操作为主的工作负载来说,吞吐量更是高出好几倍。
四、Zookeeper基本原理
4.1 Zookeeper系统架构
首先来看一下Zookeeper的系统架构图:

-
(1)ZooKeeper分为服务器端(Server) 和客户端(Client),客户端可以连接到整个 ZooKeeper服务的任意服务器上(除非 leaderServes 参数被显式设置, leader 不允许接受客户端连接)。
-
(2)客户端使用并维护一个 TCP 连接,通过这个连接发送请求、接受响应、获取观察的事件以及发送心跳。如果这个 TCP 连接中断,客户端将自动尝试连接到另外的 ZooKeeper服务器。客户端第一次连接到 ZooKeeper服务时,接受这个连接的 ZooKeeper服务器会为这个客户端建立一个会话。当这个客户端连接到另外的服务器时,这个会话会被新的服务器重新建立。
-
(3)上图中每一个Server代表一个安装Zookeeper服务的机器,即是整个提供Zookeeper服务的集群(或者是由伪集群组成);
-
(4)组成ZooKeeper服务的服务器必须彼此了解。 它们维护一个内存中的状态图像,以及持久存储中的事务日志和快照, 只要大多数服务器可用,ZooKeeper服务就可用;
-
(5)ZooKeeper 启动时,将从实例中选举一个 leader,Leader 负责处理数据更新等操作,一个更新操作成功的标志是当且仅当大多数Server在内存中成功修改数据。每个Server 在内存中存储了一份数据。
-
(6)Zookeeper是可以集群复制的,集群间通过Zab协议(Zookeeper Atomic Broadcast)来保持数据的一致性;
-
(7)Zab协议包含两个阶段:leader election阶段和Atomic Brodcast阶段(后面会提到)。
-
a. 集群中将选举出一个leader,其他的机器则称为follower,所有的写操作都被传送给leader,并通过brodcast将所有的更新告诉给follower。
-
b. 当leader崩溃或者leader失去大多数的follower时,需要重新选举出一个新的leader,让所有的服务器都恢复到一个正确的状态。
-
c. 当leader被选举出来,且大多数服务器完成了 和leader的状态同步后,leadder election 的过程就结束了,就将会进入到Atomic brodcast的过程。
-
d. Atomic Brodcast同步leader和follower之间的信息,保证leader和follower具有形同的系统状态。
-
4.2 Zookeeper Server的状态与角色
4.2.1 Zookeeper Server的状态
Zookeeper Server的状态有3种:
- LOOKING:当前Server不知道leader是谁,正在搜寻
- LEADING:当前Server即为选举出来的leader
- FOLLOWING:leader已经选举出来,当前Server与之同步
4.2.2 Zookeeper Server的角色
Zookeeper Server的角色主要分为以下几种:
- 领导者(leader):负责进行投票的发起和决议,更新系统状态
- 跟随者(follower):用于接受客户端请求并向客户端返回结果,在选主过程中参与投票
- 观察者(observer):可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程(没有投票权),只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
Zookeeper除了Server端,还有Client端,是请求发起方。
另外,这里我们引发几个思考:
Q1:为什么需要server?
①ZooKeeper 需保证高可用和强一致性;
②为了支持更多的客户端,需要增加更多的Server; ③Follower增多会导致投票阶段延迟增大,影响性能。Q2:在Zookeeper 中ObServer 起到什么作用?
①ObServer 不参与投票过程,只同步 leader的状态 ;
②Observers 接受客户端的连接,并将写请求转发给 leader节点 ;
③加入更多ObServer 节点,提高伸缩性,同时还不影响吞吐率。
Q3:为什么在Zookeeper中Server 数目一般为奇数?
我们知道在Zookeeper中 Leader 选举算法采用了Zab协议。Zab核心思想是当多数 Server 写成功,则任务数据写成功。
①如果有3个Server,则最多允许1个Server 挂掉。
②如果有4个Server,则同样最多允许1个Server挂掉。 既然3个或者4个Server,同样最多允许1个Server挂掉,那么它们的可靠性是一样的,所以选择奇数个ZooKeeper Server即可,这里选择3个Server。
4.3 Zookeeper的会话(session)
1、客户端通过TCP协议与独立服务器或者一个集群中的某个服务器建立会话连接。
2、会话提供顺序保障,即同一个会话中的请求以FIFO的顺序执行。如果客户端有多个并发会话,FIFO顺序在多个会话之间未必能够保持。 3、如果连接的Server出现问题,在没有超过Timeout时间时,可以连接其他节点。zookeeper客户端透明地转移一个会话到不同的服务器。 4、同一session期内的特性不变 5、当一个会话因某种原因终止,在这个会话期间创建的临时节点将会消失。Session是由谁来创建的?
- Leader:产生一个唯一的session,放到消息队列,让所有server知道
- 过半机制:保证session创建成功或者失败
4.4 数据模型znode
前面我们提到过了,Zookeeper提供了类似Linux文件系统的目录树结构:

- 层次的,目录型结构,便于管理逻辑关系
- 节点znode而非文件file
znode信息:
- 包含最大1MB的数据信息
- 记录了zxid等元数据信息
znode有两种类型,瞬时的(ephemeral,session过期就没有了)和持久的(persistent)
znode支持序列SEQUENTIAL:leader
- 短暂znode的客户端会话结束时,zookeeper会将该短暂znode删除,短暂znode不可以有子节点
- 持久znode不依赖于客户端会话,只有当客户端明确要删除该持久znode时才会被删除
znode的类型在创建时确定并且之后不能再修改
有序znode节点被分配唯一单调递增的整数。比如:客户端创建有序znode,路径为/task/task-,则zookeeper为其分配序号1,并追加到znode节点: /task/task-1。有序znode节点唯一,同时也可根据该序号查看znode创建顺序。
znode有四种形式的目录节点
- PERSISTENT
- EPHEMERAL
- PERSISTENT_SEQUENTIAL
- EPHEMERAL_SEQUENTIAL
4.5 Zookeeper事件监听机制
所有对 ZooKeeper 的读操作,都可附带一个 Watch 。一旦相应的数据有变化,该 Watch 即被触发。事件监听,是基于通知(notification)的机制:
Watcher 在 ZooKeeper 是一个核心功能,Watcher 可以监控目录节点的数据变化以及子目录的变化,一旦这些状态发生变化,服务器就会通知所有设置在这个目录节点上的Watcher,从而每个客户端都很快知道它所关注的目录节点的状态发生变化,而做出相应的反应。可以设置观察的操作:exists,getChildren,getData;可以触发观察的操作:create,delete,setData
Watch 有如下特点:
-
主动推送:Watch被触发时,由 ZooKeeper 服务器主动将更新推送给客户端,而不需要客户端轮询。
-
一次性:数据变化时,Watch 只会被触发一次。如果客户端想得到后续更新的通知,必须要在 Watch 被触发后重新注册一个 Watch。
-
可见性:如果一个客户端在读请求中附带 Watch,Watch 被触发的同时再次读取数据,客户端在得到 Watch 消息之前肯定不可能看到更新后的数据。换句话说,更新通知先于更新结果。
-
顺序性:如果多个更新触发了多个 Watch ,那 Watch 被触发的顺序与更新顺序一致。
4.6 原子广播-Zab协议
Zookeeper的核心是原子广播,该机制由Zab协议实现,保证了集群内各节点的数据一致性、数据最新。Zab协议有广播模式、恢复模式两种。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数server的完成了和leader的状态同步以后,恢复模式就结束了。
状态同步保证了leader和server具有相同的系统状态4.6.1 恢复模式
当服务启动或leader崩溃后,Zab就进入了恢复模式。恢复选主的时候,首先投票,一开始的时候,都把票投给自己,然后轮询集群中所有其他机器的选票,如果有其他机器的 zxid 大于自己(首先选zxid最大的,其次才是myid),那么就把选票投给它(通信端口3888),如果 zxid 相同就投给那个 serverid 最大的。一旦触发过半机制,即某个节点的server的选票过半,该过程终止。
在出现分区的时候,如果 leader 位于多数 follower 的一方,则该方正常,另外半边均不能读写,集群正常。如果 leader位于 少数 follower 一方,那么leader就不能站稳脚跟,多数方就要重新选举出新leader。
新leader确定后,zk集群内的leader、follower开始同步恢复状态,一旦过半的服务器完成数据同步,就结束恢复模式。如果有新的成员服务器加入集群,那它会在恢复模式下启动、与leader同步状态,一旦同步结束,就立刻参与到广播中来。
上述选举过程会在200ms内完成,速度非常快!

4.6.1.1 leader选举算法
可通过electionAlg配置项设置ZooKeeper用于领导选举的算法,到3.4.10版本为止,可选项有:
-
基于UDP的LeaderElection
-
基于UDP的FastLeaderElection
-
基于UDP和认证的FastLeaderElection
-
基于TCP的FastLeaderElection
在3.4.10版本中,默认是基于TCP的FastLeaderElection。另外三种算法已经被弃用,并且有计划在之后的版本中将它们彻底删除而不再支持。
4.6.2 广播模式
广播模式需要保证proposal被按顺序处理,因此zk采用了递增的事务id号(zxid)来保证。
所有的提议(proposal)都在被提出的时候加上了zxid(zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,低32位是个递增计数)。广播模式的精髓,就在于两阶段提交:
客户端向follower发起一个增删改的请求,follower无权处理,便把请求转发给leader老大(通信端口2888)。leader老大拿到之后,就通过广播发起投票:我要做这个事,你们同意不?(将写请求以Proposal的形式发给所有Follower并等待ACK)。follower收到leader的广播就要做出反应了(Follower收到Leader的Proposal后返回ACK),只要leader收到过半的投票(ACK,leader对自己也有一票),就意味着leader要着手做这件事了,便向所有的follower、observer发送一个submit命令,如:创建一个节点。follower完成该任务后,便回应Client说:我搞完了。倘若曾经leader没有收到过半投票,那么follower便向Client回应:你这个事做不了!

-
Leader并不需要得到Observer的ACK,即Observer无投票权
-
Leader不需要得到所有Follower的ACK,只要收到过半的ACK即可,同时Leader本身对自己有一个ACK。
-
Observer虽然无投票权,但仍须同步Leader的数据从而在处理读请求时可以返回尽可能新的数据
五、配置文件的属性
在conf目录下创建一个配置文件zoo.cfg:
tickTime=2000 dataDir=/Users/zdandljb/zookeeper/datadataLogDir=/Users/zdandljb/zookeeper/dataLogclientPort=2181initLimit=5syncLimit=2server.1=server1:2888:3888server.2=server2:2888:3888server.3=server3:2888:3888 observer #表示对应节点不参与投票
tickTime:发送心跳的间隔时间,单位:毫秒
dataDir:zookeeper保存数据的目录。
clientPort:客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
initLimit: 这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接Zookeeper服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader的Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 5 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10秒
syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个tickTime 的时间长度,总的时间长度就是 2*2000=4 秒
server.A=B:C:D:其 中 A 是一个数字,表示这个是第几号服务器;B 是这个服务器的ip地址;C 表示的是这个服务器与集群中的Leader服务器交换信息的端口;D表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于B都是一样,所以不同的Zookeeper实例通信端口号不能一样,所以要给它们分配不同的端口号。
六、Zookeeper操作命令
节点中保存的数据,不超过1M。
列表显示: ls / 创建节点:create /husky hello 获取节点信息:get /husky 修改:set /husky myworld 在节点下创建子节点:create /mynode/mynode01 “” 创建临时节点:create -e /tmp haha 创建序列化节点:create -s /seqnode hehe发表评论
最新留言
关于作者
