文章目录
1.是什么
是一个开源的分布式协调服务,是由雅虎创建的,基于google chubby,分布式数据一致性的解决方案
2.安装
2.1 单机
参见:https://blog.csdn.net/wrs120/article/details/79980434
2.2 集群
-
复制单机
-
修改zoo.conf ,添加每台服务的server.id=host:port:port(
id:取值范围1~255,id标识该机器在集群中的机器序号;
host:服务器所在机器的IP地址
第一个port:zookeeper的端口号,用来leader与flower之间数据同步
第二个port:用于leader之间投票选举master -
每台服务创建myid文件
在每台服务器的dataDir目录下创建一个myid文件,文件就一行数据,内容为每台服务器对应的server ID的数字
2.3 配置文件讲解
tickTime=2000 //zookeeper中最小的时间ms
initLimit=10 //follower节点启动后与leader节点完成数据同步的时间 initLimit * tickTime
syncLimit=5 // leader节点和follower节点进行心跳检测的最大延迟时间
dataDir=/root/zookeeper-3.4.6/data //zookeeper服务器存储快照文件的目录
clientPort=2181 // 客户端连接服务端的端口号
dataLogDir=/tmp/zookeeper //zookeeper事务日志的存储路径,最好和dataDir分开
2.3 操作
增删改。。。
3. 相关概念
3.1 数据模型
zookeeper的数据模型和文件系统类似,每一个节点成为znode,是zookeeper的最小数据单元;每个节点都可保存数据和挂载子节点,从而构成一个层次化的属性结构
节点分类及特性:
- 持久化节点:节点创建后会一直存储在zookeeper服务端,知道主动删除
- 持久化有序节点:每个节点会为它的一级子节点维护一个顺序
- 临时节点:生命周期和客户端的会话保持一致,当客户端会话失效,该节点清除
- 临时有序节点:在临时节点上都了一个顺序性特点
节点详细信息:
可以使用get命令可以获取指定ZNode的数据内容和属性信息:
[zk: localhost:2181(CONNECTED) 12] get /zk-huey
000
cZxid = 0x20000007c
ctime = Wed Mar 04 22:01:46 CST 2015
mZxid = 0x20000007c
mtime = Wed Mar 04 22:01:46 CST 2015
pZxid = 0x200000080
cversion = 4
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 4
输出的第一行是ZNode的数据内容,后面则是ZNode的状态信息。状态信息的属性说明如下:
状态属性 | 说明 |
cZxid | 数据节点创建时的事务ID |
ctime | 数据节点创建时的时间 |
mZxid | 数据节点最后一次更新时的事务ID |
mtime | 数据节点最后一次更新时的时间 |
pZxid | 数据节点的子节点列表最后一次被修改(是子节点列表变更,而不是子节点内容变更)时的事务ID |
cversion | 子节点的版本号 |
dataVersion | 数据节点的版本号 |
aclVersion | 数据节点的ACL版本号 |
ephemeralOwner | 如果节点是临时节点,则表示创建该节点的会话的SessionID;如果节点是持久节点,则该属性值为0 |
dataLength | 数据内容的长度 |
numChildren | 数据节点当前的子节点个数 |
3.2会话
客户端连接服务端时会先创建一个句柄,这就产生了一个会话。即客户端与服务端保持TCP连接的整个过程。客户端与服务端之间任何交互操作都与会话息息相关,如临时节点的生命周期、客户端请求的顺序执行、Watcher通知机制等。会话分为4中状态:
- not_connected
- connecting
- connected
- closed
转换顺序:
3.3 Watcher
zookeeper提供了分布式数据发布/订阅功能,zookeeper允许客户端向服务器注册一个watcher监听。当服务器端的节点触发制定事件的时候就会触发watcher,此时服务端会向客户端发送一个事件通知。(典型的观察者模式)watcher有以下几大特点:
- 一次性:watcher的通知是一次性的,一旦触发一次通知后,该watcher就失效。要想始终节点,可以循环注册watcher
- 客户端串行执行 :客户端 Watcher 回调的过程是一个串行同步的过程,这为我们保证了顺序,同时,需要注意的一点是,一定不能因为一个 Watcher 的处理逻辑影响了整个客户端的
Watcher 回调,所以,我觉得客户端 Watcher 的实现类要另开一个线程进行处理业务逻辑,以便给其他的 Watcher
调用让出时间 - 轻量 :WatcherEvent 是 ZooKeeper 整个 Watcher 通知机制的最小通知单元,这个数据结构中只包含三部分内容:通知状态、事件类型和节点路径。也就是说,Watcher 通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。例如针对 NodeDataChanged 事件,ZooKeeper 的Watcher 只会通知客户端指定数据节点的数据内容发生了变更,而对于原始数据以及变更后的新数据都无法从这个事件中直接获取到,而是需要客户端主动重新去获取数据——这也是 ZooKeeper 的 Watcher 机制的一个非常重要的特性
有5种情况可能会触发watcher(看用户注册了哪个事件)0,即WatcherEventL的EventType事件类型:
- None:客户端与服务端建立会话,状态发生改变的时候,事件就是none
- NodeCreated:节点创建
- NodeDeleted:节点删除
- NodeDataChanged:节点内容改变
- NodeChildrenChanged:子节点创建,删除时,不包括自己点内容变化
ZooKeeper 的 Watcher 机制主要包括客户端线程、客户端 WatchManager 和 ZooKeeper 服务器三部分, 在上图中:
- ZooKeeper :部署在远程主机上的 ZooKeeper 集群,当然,也可能是单机的。
- Client :分布在各处的 ZooKeeper 的 jar 包程序,被引用在各个独立应用程序中。
- WatchManager :一个接口,用于管理各个监听器,只有一个方法 materialize(),返回一个 Watcher 的 set。
在具体流程上,简单讲,客户端在向 ZooKeeper 服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的 WatchManager 中。当ZooKeeper 服务器触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatchManager 的实现类中取出对应的 Watcher 对象来执行回调逻辑。
3.4 ACL权限控制列表
是Access control lists 的缩写,权限控制列表
- 针对节点可以设置相关读写等权限,目的是为了保障数据安全性
- 权限permissions可以指定不同的权限范围以及角色
ACL的构成(zk的acl通过 [scheme: id :permissions] 来构成权限列表):
-
scheme:代表采用的某种权限机制
-
id:代表允许访问的用户
-
permissions:权限组合字符串
ACL的构成scheme的种类:
- world:world下只有一个id,即只有一个用户,也就是anyone,那么组合的写法就是
world:anyone:[permissions] - ip:当设置为ip指定的ip地址,此时限制ip进行访问,比如ip:192.168.77.130:[permissions]
- auth:代表认证登录,需要注册用户获取权限后才可以登录访问,形式为 auth:userpassword:[permissions]
- digest:需要对密码加密才能访问,组合形式为:digest:username:BASE64(SHA1(password)):[permissions]
- auth与digest的区别就是,前者使用明文密码进行登录,后者使用密文密码进行登录。setAcl /path auth:lee:lee:cdrwa 与 setAcl /path digest:lee:BASE64(SHA1(password)):cdrwa是等价的,在通过 addauth digest lee:lee 后都能操作指定节点的权限。在实际情况中,digest要更为常用一些。
- super:代表超级管理员,拥有所有的权限
acl的构成-permissions(权限字符串缩写 crdwa):
-
CREATE:创建子节点权限
-
READ:访问节点/子节点权限
-
WRITE:设置节点数据权限
-
DELETE:删除子节点权限
-
ADMIN:管理员权限
acl命令:
- getAcl 获取某个节点的acl权限信息
- setAcl 设置某个节点的acl权限信息
- addauth 输入认证授权信息,注册时输入明文密码(登录),但是在zk的系统里,密码是以加密后的形式存在的
更多详细内容,参见:https://blog.51cto.com/zero01/2106801
4. 应用场景
4.1 数据的发布/订阅
数据订阅有两种模式:推模式(服务器主动向客户端推送消息)和拉模式(客户端主动向服务端获取数据,通常以轮询方式),zk采用两种方式相结合:发布者将消息发布到zk集群节点上,订阅者将感兴趣的点注册到zk集群节点上,当服务器节点数据发生变化时就通知客户端(推),客户端得到通知后就去服务器获取数据(拉)
4.2 统一配置中心
配置中心使用ZooKeeper的持久节点的特性,zk启动时,从数据库读取信息,将配置信息写入到持久节点。客户端启动时,从ZooKeeper读取配置信息,进而初始化内部资源,达到配置统一管理的目的。再结合ZooKeeper的Watch特性,配置信息变化实时推送到客户端,即时生效,无需重启客户端,达到配置热更新的效果;如果要更改信息,先修改持久化节点的内容,然后持久化到DB,再更新到zk,然后各子应用监听数据变化
4.3 负载均衡(dubbo利用zookeeper机制实现负载均衡)
zk有持久节点和临时节点,服务会注册到zk上,客户端连接服务端时就选择一个可用的服务端,如果此台服务出现问题时,它代表的临时节点就会消失,客户端会再重新连接一个可用连接
4.4 master选举
利用zab协议
4.5 分布式锁
基于zookeeper分布式锁的流程:
- 在zookeeper指定节点(locks)下创建临时顺序节点node_n
- 获取locks下所有子节点children
- 对子节点按节点自增序号从小到大排序
- 判断本节点是不是第一个子节点,若是,则获取锁;若不是,则注册watcher监听比该节点小的那个节点的删除事件
- 若监听事件生效,则回到第二步重新进行判断,直到获取到锁
在实现zookeeper分布式锁的过程中:会涉及到CountDownLatch,推荐两篇相关文章:CountDownLatch详解;CountDownLatch、CyclicBarrier、Semaphore的区别, 其中在设计时,还用过ReentrantLock,分为公平锁和非公平锁
总结:之所以有这些特性,利用的是zookeeper对数据的监控,需要明白的一点:zookeeper并不是用来存储数据的,通过监控数据状态的变化,达到基于数据的集群管理
5. 特性
- 顺序性
从同一个客户端发起的请求,最终会按请求的顺序注册到zookeeper中 - 原子性
所有的事务请求处理结果在整个集群中所有的机器上应用情况是一致的。即整个集群中所有机器要么都应用某一个事务,要么全都不应用 - 可靠性
一旦服务器端提交了某个事务并且获得了服务端返回的成功的标识,那么这个数据在整个集群中一定是同步并且保留下来的 - 实时性
一旦某个事务被成功应用,客户端立即从服务端接收到事务变更后的最新数据状态(近实时) - 单一视图
无论客户端连接到哪台服务器,看到的模型都是一样的
6. 数据存储
zk中数据分为两种:
- 内存数据:真正提供服务的数据
- 磁盘数据:用于数据恢复和数据同步
7. 集群角色
7.1 角色种类及区别
集群中一共有3中角色:
-
leader角色
接收所有Follower的提案请求并统一协调发起提案的投票,负责与所有的follower进行内部数据交换(同步),下面是leader的特点:- zookeeper的关键部位;
- 处理写事务;
-
follower角色
直接为客户端服务并参与提案的投票,同时与leader进行数据交换,下面是follower的特点:- 处理读请求
- 转发写请求(如果写请求发送到了follower上,那么该写请求会转发到leader上)
-
observer角色
直接为客户端服务但不参与提案的投票,同时也与leader进行数据交换(同步),下面说一下为什么会出现observer角色及observer的特点:- 是一种特殊的zookeeper节点
- 当访问量增大时,这时需要增加服务器的数量,但是zookeeper集群中数据的变更需要半数以上服务器投票通过才行,这样增多服务器后就增加了投票造成的网络消耗,增加了投票的成本,降低了zookeeper的写性能,此时就可以把新加入的机器设置为observer类型。这样在提高了集群的读性能的同时,也没增加写的成本
- observer不参与投票,只接收数据更改状态
- 不属于zookeeper的关键部位
7.2 leader,follower,observer之间的通信
下图展示了客户端发送请求到服务端的过程:
-
客户端的写请求最后一点会发送到leader
-
客户端的读请求,会根据算法分配到不同节点
-
不影响写性能的情况下用observer扩展了zookeeper
7.3 选举方式
7.3.1 zk器群启动的选举流程
下面以5台服务器组成的zookeeper集群,编号分别为1,2,3,4,5为例(启动时都是先给自己投票,先比较zxid,再比较myid)):
- 编号1的zk服务器启动,给自己投票(myId,zxid)(1,0),此时还没收到其它服务器的反馈信息,然后进入looking状态
- 编号2的zk服务器启动了,同样给自己投票(myId,zxid)(2,0),这时接收到编号1发来的消息(1,0),zxid一样,但是myid比编号1的服务大,不再投票,此时编号1接收到(2,0),myid比自己大,再次发送广播(2,0),这样编号1和编号2都一致投票给2号,但这时2号才收到2票,2<5/2,票数还没过半,无法成为leader
- 编号3的zk服务器启动了,同样给自己投票(3,0),编号1和编号2收到(3,0)都是自己大,编号1和编号2发送广播(3,0),这是编号3收到3票,已超过半数,编号3成为leadering,编号1和2把looking改为followering
- 编号4的zk服务器启动了,已经有leader了,就从leader那边同步信息,成为follower
- 编号5的自考服务器启动了,已经有leader了,就从leader那边同步信息,成为follower
7.3.2 宕机后选举的选举流程
过程和启动时一样,只不过此时zxid的作用更大了,这是的zxid有高有低,不过最大的zxid会被选举成为leader,这样才能保证最新的节点成为leader之后其他旧的zxid的节点能同步到最新
注:
-
zxid: 致使ZooKeeper节点状态改变的每一个操作都将使节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。也就是说,每个对节点的改变都将产生一个唯一的Zxid。如果Zxid1的值小于Zxid2的值,那么Zxid1所对应的事件发生在Zxid2所对应的事件之前。实际上,ZooKeeper的每个节点维护者两个Zxid值,为别为:cZxid、mZxid。
- cZxid: 是节点的创建时间所对应的Zxid格式时间戳。
- mZxid:是节点的修改时间所对应的Zxid格式时间戳。
实现中Zxid是一个64为的数字,它高32位是epoch用来标识Leader关系是否改变,每次一个Leader被选出来,它都会有一个新的epoch。低32位是个递增计数。
-
epoch: 选举的轮数
-
server的状态ServerState: LOOKING, FOLLOWING, LEADING, OBSERVING
- LOOKING:初始状态,表示在选举leader
- FOLLOWING:跟随leader的角色,参与投票
- LEADING:集群的leader
- OBSERVING:不参与投票,只是同步状态
7.3.3 选举算法
共有3种: leaderElection,AuthFastLeaderElection,FastLeaderElection ,默认为FastLeaderElection算法
7.3.4 选举机制
zookeeper并没有完全采用paxos算法, 而是采用zab(Zookeeper atomic broadcast)
zab协议的原理
- 在zookeeper 的主备模式下,通过zab协议来保证集群中各个副本数据的一致性
- zookeeper使用的是单一的主进程来接收并处理所有的事务请求,并采用zab协议,
把数据的状态变更以事务请求的形式广播到其他的节点 - zab协议在主备模型架构中,保证了同一时刻只能有一个主进程来广播服务器的状态变更
- 所有的事务请求必须由全局唯一的服务器来协调处理,这个的服务器叫leader,其他的叫follower
leader节点主要负责把客户端的事务请求转化成一个事务提议(proposal),并分发给集群中的所有follower节点
再等待所有follower节点的反馈。一旦超过半数服务器进行了正确的反馈,那么leader就会commit这条消息
什么情况下zab协议会进入崩溃恢复模式
- 当服务器启动时
- 当leader服务器出现网络中断、崩溃或者重启的情况
- 集群中已经不存在过半的服务器与该leader保持正常通信
zab协议进入崩溃恢复模式会做什么
- 当leader出现问题,zab协议进入崩溃恢复模式,并且选举出新的leader。当新的leader选举出来以后,如果集群中已经有过半机器完成了leader服务器的状态同(数据同步),退出崩溃恢复,进入消息广播模式
- 当新的机器加入到集群中的时候,如果已经存在leader服务器,那么新加入的服务器就会自觉进入数据恢复模式,找到leader进行数据同步
更多关于zab的知识,参见这篇非常好的文章:https://blog.csdn.net/fu123123fu/article/details/81208847