ZooKeeper
zookeeper
前言
在现在分布式、微服务大行其道的今天,肯定都会接触ZooKeeper这个框架。本人也只是在Dubbo的项目中有使用过(当然Kafka的集群部署也是基于ZooKeeper,这个就不算使用了)。但是它可以做的事远不止在Dubbo中的使用。所以先了解了ZooKeeper的基本模型、概念以及使用,以便加深学习
zookeeper是什么
ZooKeeper 是一个开源的分布式协调服务,设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。
ZooKeeper 是一个典型的分布式数据一致性解决方案。其主要应用场景:
- master节点选举,主节点挂了以后,从节点就会接收工作,并且节点是唯一的。保证高可用(比如Kafka集群)
- 统一配置文件管理,即只需要部署一台服务器,则可以把相同的配置文件同步更新到其他服务器。
- 发布与订阅。类似于消息队列MQ,dubbo发布者把数据发布到znode上,订阅者会拉出数据
- 分布式锁
- 集群管理,集群中保证数据的强一致性(Dubbo的注册中心)
本人主要接触ZooKeeper还是在公司使用Dubbo的时候接触的,所以ZooKeeper主要是用于:服务的容错、负载均衡、查找服务和管理服务,还可以选择其作为配置中心的集中式管理。
ZooKeeper的数据模型
Session机制
在了解ZooKeeper的数据模型之前,有必要了解ZooKeeper的Session机制
Session是指客户端和服务端之间会话。在ZooKeeper中是指一个客户端与ZooKeeper之间的一次长连接。客户端在启动时会与服务端建立一个Tcp连接。后续客户端可已通过这个连接发送消息给服务端,也可以监听服务端发送来的消息。客户端和服务端有一个心跳机制来维持和判断这个连接的有效性,可以通过Session中的sessionTimeout
值来设置一个客户端的超时时间。同时当由于服务器原因或者客户端主动要求端口连接的时候,只要在超时时间内重新连接任一一台ZooKeeper机器,那么之前创建的 Session仍然有效。
和我们平常接触到HttpSession一样,每次创建一次会话,服务端都会为该客户端分配一个SessionId,该SessionId也是全局唯一的。
数据模型
ZooKeeper的数据模型和我们经常使用的Unix/Linux的文件系统是类似的。
上图中我们可以比较明显看到和文件系统很像,实际它提供的操作API都有点类似。正确情况下,我们会在会根目录下创建一个自己项目的Znode。比如dubbo、kafka以便隔离数据。和我们创建文件夹的思路一样
znode
- 在ZooKeeper中每一个节点都称之为znode,它本身可以有子节点,也可以有数据。
- 每一个节点分为临时节点和永久节点,临时节点在客户端断开后消失。也就是Session超时
- 每一个节点都有各自的版本号。可以通过命令行来显示节点信息
- 没当节点的数据发生改变,那么该节点的版本号都会累加(乐观锁)
- 删除、修改节点时,如果版本号不匹配会报错(乐观锁)
- 由于ZooKeeper的数据都存在内存中,每个节点的数据不建议存储过大的数据。几K即可
- 节点也可以设置acl权限。可以通过权限来限制用户的操作(unix的文件权限)
这里需要注意znode分为临时节点和永久节点,临时节点在session关闭时会自动删除
watch机制
ZooKeeper在针对每个节点的操作,都会有监督者(watcher),当监控对象znode发生了变化,则触发watcher事件,可以理解为监听器。zk中的watcher是一次性的,触发后立即销毁
父节点、子节点 增删改都能够触发watcher事件。 具体的watcher事件
- 创建节点触发, NodeCreated
- 修改节点触发,NodeDataChanged
- 删除节点触发,NodeDeleted
- 增加子节点触发,NodeChildrenChanged
- 删除子节点触发,NodeChildrenChanged
- 修改子节点不触发监听
这里我建议自己在命令行或者用代码api来自己体验下
ZooKeeper命令行
了解基本的命令行,其实ZooKeeper的命令行并不多,这里只做简单介绍
执行./zkCli.sh
即可打开命令行
查询命令
ls path [watch] 查询目录
watch 设置子节点的watch事件
stat path [watch] 查询详细信息
watch 设置当前节点的watch事件(下面的watch都是类似的机制不在说明)
节点信息如下:
- cZxid 创建的id
- ctime 创建的时间
- mZxid 修改的id
- mtime 修改的时间
- pZxid 父节点的id
- cversion 子节点的version
- dataVersion 数据的version
- aclVersion 权限的version
- ephemeraOwner 0x0为永久节点,其他为临时节点(待定)
- datalength 数据长度
- numChildren 子节点的大小
zxid:ZooKeeper状态的每一次改变, 都对应着一个递增的Transaction id, 该id称为zxid. 由于zxid的递增性质, 如果zxid1小于zxid2, 那么zxid1肯定先于zxid2发生
创建任意节点, 或者更新任意节点的数据, 或者删除任意节点, 都会导致Zookeeper状态发生改变, 从而导致zxid的值增加.
ls2 path [watch] 查询目录,同时展示节点的信息
get path [watch] 可以将目录的数据取出来
创建命令
create [-s] [-e] path data acl
-e 临时节点
-s 顺序节点 在创建文件夹会在后面自动添加1开始的顺序
create /test/name hello-world
修改命令
set path data [version]
version 主要用于更新时的乐观锁
删除命令
delete path [version]
version 主要用于删除时的乐观锁
ZooKeeper的集群
前面已经了解的ZooKeeper的概念,已经他能够为我们做什么。现在来了解一下ZooKeeper是怎么保证数据的统一性。以及自身集群的高可用。
ZooKeeper 中的角色
ZooKeeper在实际生产环境中是推荐使用集群方式。
在ZooKeeper的集群中引入了Leader、Follower、Observer三种角色。如下图所示
ZooKeeper集群中的所有机器会通过Leader选举过程来选定一台成为Leader的机器。
该Leader既可以为客户端提供读服务和写服务,但是Follower和Observer都只能提供读服务。Follower和Observer的唯一区别就是不参与Leader的选举过程,Observer仅仅是用提升服务的读取速度而存在的。因为Follower的无限增多也会影响选举的性能。
ZooKeeper的核心是原子广播,这个机制保证各个Server之间的同步。实现这个机制的协议叫Zab协议。Zab协议有两种模式:恢复模式(选主)和广播模式(同步)
当Leader服务器出现崩溃,重启,网络中断等异常情况时,Zab协议会进入恢复模式并选举出新的Leader服务
大致步骤如下:
- Leader election(选举阶段):节点在一开始都处于选举阶段,只要有一个节点得到超半数节点的票数,它就可以当选准 leader。
- Discovery(发现阶段):在这个阶段,followers 跟准 leader 进行通信,同步 followers 最近接收的事务提议。
- Synchronization(同步阶段):同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。同步完成之后 准 leader 才会成为真正的 leader。
- Broadcast(广播阶段) 到了这个阶段,Zookeeper 集群才能正式对外提供事务服务,并且 leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步。
这里通过第一条的规则,所以ZooKeeper部署推荐为单数服务,假如3台机器。最大允许宕机一台。而四台机器也是最大允许宕机一台。所以并不推荐部署双数机器部署
ZooKeeper的读写机制
- Zookeeper是一个由多个server组成的集群
- 一个leader,多个follower
- 每个server保存一份数据副本
- 全局数据一致
- 分布式读写
- 更新请求转发,由leader实施
Zookeeper的保证
- 更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
- 数据更新原子性,一次数据更新要么成功,要么失败
- 全局唯一数据视图,client无论连接到哪个server,数据视图都是一致的
- 实时性,在一定事件范围内,client能读到最新数据
Zookeeper的选举方式
首先选举必须要半数通过才行
简单模拟一下:
- A提案说,我要选自己,B你同意吗?C你同意吗?B说,我同意选A;C说,我同意选A。(注意,这里超过半数了,其实在现实世界选举已经成功了。但是计算机世界是很严格,另外要理解算法,要继续模拟下去。)
- 接着B提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;C说,A已经超半数同意当选,B提案无效。
- 接着C提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;B说,A已经超半数同意当选,C的提案无效。
- 选举已经产生了Leader,后面的都是follower,只能服从Leader的命令。而且这里还有个小细节,就是其实谁先启动谁当头。
Zab协议和Paxos算法
Paxos算法应该可以说是ZooKeeper的灵魂了。但是ZooKeeper并没有完全采用Paxos算法 ,而是使用ZAB协议作为其保证数据一致性的核心算法。另外,在ZooKeeper的官方文档中也指出,ZAB协议并不像Paxos算法那样,是一种通用的分布式一致性算法,它是一种特别为Zookeeper设计的崩溃可恢复的原子消息广播算法。
这里Paxos算法暂时没什么了解,可以参考一些文章和一些书籍了解
总结
- ZooKeeper本身就是一个分布式程序。超过半数以上存活,ZooKeeper就能正常服务
- ZooKeeper的数据保存在内中,保证低延迟和高吞吐量,也不建议在znode中保存过大的数据
- ZooKeeper推荐使用在读多写少的场景写,上面我们可以到了ZooKeeper只有leader才能执行写操作,这样做确实天然的保证的其顺序性,但是也影响了性能
- znode有临时节点和永久节点的区分,临时节点在Session关闭时删除。(Session的关闭时通过Session超时来决定的,如果断开后再超时时间连上来Session是会继续维持)
- ZooKeeper对于客户端主要提供两个操作:数据的增删改查和数据的监听服务
参考
原文作者: duteliang
原文链接: http://yoursite.com/2019/12/30/microservices/zookeeper/
版权声明: 转载请注明出处(必须保留原文作者署名原文链接)