ZK的特性
Zk的特性会从会话、数据节点,版本,Watcher,ACL权限控制,集群角色这些部分来了解,其中重点需要掌握的数据节点与Watcher
会话
客户端与服务端的一次会话连接,本质是TCP长连接,通过会话可以进行心跳检测和数据传输;
会话(session)是zookepper非常重要的概念,客户端和服务端之间的任何交互操作都与会话有关
会话状态
看下这图,Zk客户端和服务端成功连接后,就创建了一次会话,ZK会话在整个运行期间的生命周期中,会在不同的会话状态之间切换,这些状态包括:
CONNECTING、CONNECTED、RECONNECTING、RECONNECTED、CLOSE
一旦客户端开始创建Zookeeper对象,那么客户端状态就会变成CONNECTING状态,同时客户端开始尝试连接服务端,连接成功后,客户端状态变为CONNECTED,通常情况下,由于断网或其他原因,客户端与服务端之间会出现断开情况,一旦碰到这种情况,Zookeeper客户端会自动进行重连服务,同时客户端状态再次变成CONNCTING,直到重新连上服务端后,状态又变为CONNECTED,在通常情况下,客户端的状态总是介于CONNECTING和CONNECTED之间。但是,如果出现诸如会话超时、权限检查或是客户端主动退出程序等情况,客户端的状态就会直接变更为CLOSE状态
ZK数据模型
ZooKeeper的视图结构和标准的Unix文件系统类似,其中每个节点称为“数据节点”或ZNode,每个znode可以存储数据,还可以挂载子节点,因此可以称之为“树”
第二点需要注意的是,每一个znode都必须有值,如果没有值,节点是不能创建成功的。
在Zookeeper中,znode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储或获取数据
通过客户端可对znode进行增删改查的操作,还可以注册watcher监控znode的变化。
Zookeeper节点类型
节点类型非常重要,是后面项目实战的基础。
a、Znode有两种类型:
短暂(ephemeral)(create -e /app1/test1 “test1” 客户端断开连接zk删除ephemeral类型节点)
持久(persistent) (create -s /app1/test2 “test2” 客户端断开连接zk不删除persistent类型节点)
b、Znode有四种形式的目录节点(默认是persistent )
PERSISTENT
PERSISTENT_SEQUENTIAL(持久序列/test0000000019 )
EPHEMERAL
EPHEMERAL_SEQUENTIAL
c、创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护
d、在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序
命令行
服务端常用命令
在准备好相应的配置之后,可以直接通过zkServer.sh 这个脚本进行服务的相关操作
启动ZK服务: sh bin/zkServer.sh start ·
查看ZK服务状态: sh bin/zkServer.sh status ·
停止ZK服务: sh bin/zkServer.sh stop ·
重启ZK服务: sh bin/zkServer.sh restart
客户端常用命令
使用 zkCli.sh -server 127.0.0.1:2181 连接到 ZooKeeper 服务,连接成功后,系统会输出 ZooKeeper 的相关环境以及配置信息。 命令行工具的一些简单操作如下:
显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
创建文件,并设置初始内容: create /zk "test" 创建一个新的 znode节点“ zk ”以及与它关联的字符串 [-e] [-s] 【-e 零时节点】 【-s 顺序节点】
获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串 [watch]【watch 监听】
修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置 ·
删除文件: delete /zk 将刚才创建的 znode 删除,如果存在子节点删除失败
递归删除:rmr /zk将刚才创建的 znode 删除,子节点同时删除
退出客户端: quit ·
帮助命令: help
ACL命令常用命令
Zookeeper的ACL(Access Control List),分为三个维度:scheme、id、permission
通常表示为:scheme:id:permission
l schema:代表授权策略
l id:代表用户
l permission:代表权限
Scheme
world:
默认方式,相当于全世界都能访问
auth:
代表已经认证通过的用户(可以通过addauth digest user:pwd 来添加授权用户)
digest:
即用户名:密码这种方式认证,这也是业务系统中最常用的
ip:
使用Ip地址认证
id
id是验证模式,不同的scheme,id的值也不一样。
scheme为auth时:
username:password
scheme为digest时:
username:BASE64(SHA1(password))
scheme为ip时:
客户端的ip地址。
scheme为world时
anyone。
Permission
CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、删、改、查、管理权限,这5种权限简写为crwda(即:每个单词的首字符缩写)
CREATE(c):创建子节点的权限
DELETE(d):删除节点的权限
READ(r):读取节点数据的权限
WRITE(w):修改节点数据的权限
ADMIN(a):设置子节点权限的权限
ACL命令
getAcl
获取指定节点的ACL信息
create /testDir/testAcl deer # 创建一个子节点
getAcl /testDir/testAcl # 获取该节点的acl权限信息
setAcl
设置指定节点的ACL信息
setAcl /testDir/testAcl world:anyone:crwa # 设置该节点的acl权限
getAcl /testDir/testAcl # 获取该节点的acl权限信息,成功后,该节点就少了d权限
create /testDir/testAcl/xyz xyz-data # 创建子节点
delete /testDir/testAcl/xyz # 由于没有d权限,所以提示无法删除
addauth
注册会话授权信息
Auth
addauth digest user1:123456 # 需要先添加一个用户
setAcl /testDir/testAcl auth:user1:123456:crwa # 然后才可以拿着这个用户去设置权限
getAcl /testDir/testAcl # 密码是以密文的形式存储的
create /testDir/testAcl/testa aaa
delete /testDir/testAcl/testa # 由于没有d权限,所以提示无法删除
退出客户端后:
ls /testDir/testAcl #没有权限无法访问
create /testDir/testAcl/testb bbb #没有权限无法访问
addauth digest user1:123456 # 重新新增权限后可以访问了
Digest
auth与digest的区别就是,前者使用明文密码进行登录,后者使用密文密码进行登录
create /testDir/testDigest data
addauth digest user1:123456
setAcl /testDir/testDigest digest:user1:HYGa7IZRm2PUBFiFFu8xY2pPP/s=:crwa # 使用digest来设置权限
注意:这里如果使用明文,会导致该znode不可访问
通过明文获得密文
shell>
java -Djava.ext.dirs=/soft/zookeeper-3.4.12/lib -cp /soft/zookeeper-3.4.12/zookeeper-3.4.12.jar org.apache.zookeeper.server.auth.DigestAuthenticationProvider deer:123456
deer:123456->deer:ACFm5rWnnKn9K9RN/Oc8qEYGYDs=
1.1.1.1.1. acl命令行ip
create /testDir/testIp data
setAcl /testDir/testIp ip:192.168.30.10:cdrwa
getAcl /testDir/testIp
常用四字命令
ZooKeeper 支持某些特定的四字命令字母与其的交互。用来获取 ZooKeeper 服务的当前状态及相关信息。可通过 telnet 或 nc 向 ZooKeeper 提交相应的命令 :
当然,前提是安装好了nc
echo stat|nc 127.0.0.1 2181 来查看哪个节点被选择作为follower或者leader ·
使用echo ruok|nc 127.0.0.1 2181 测试是否启动了该Server,若回复imok表示已经启动。 ·
echo dump| nc 127.0.0.1 2181 ,列出未经处理的会话和临时节点。 ·
echo kill | nc 127.0.0.1 2181 ,关掉server ·
echo conf | nc 127.0.0.1 2181 ,输出相关服务配置的详细信息。 ·
echo cons | nc 127.0.0.1 2181 ,列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息 ·
echo envi |nc 127.0.0.1 2181 ,输出关于服务环境的详细信息(区别于 conf 命令)。 ·
echo reqs | nc 127.0.0.1 2181 ,列出未经处理的请求。 ·
echo wchs | nc 127.0.0.1 2181 ,列出服务器 watch 的详细信息。 ·
echo wchc | nc 127.0.0.1 2181 ,通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。 ·
echo wchp | nc 127.0.0.1 2181 ,通过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路径。
ZooKeeper 日志可视化
前面以及讲了两个非常重要的配置一个是dataDir,存放的快照数据,一个是dataLogDir,存放的是事务日志文件
java -cp /soft/zookeeper-3.4.12/zookeeper-3.4.12.jar:/soft/zookeeper-3.4.12/lib/slf4j-api-1.7.25.jar org.apache.zookeeper.server.LogFormatter log.1
java -cp /soft/zookeeper-3.4.12/zookeeper-3.4.12.jar:/soft/zookeeper-3.4.12/lib/slf4j-api-1.7.25.jar org.apache.zookeeper.server.SnapshotFormatter log.1
ZK集群解析
Zookeeper集群特点
前面一种研究的单节点,现在来研究下zk集群,首先来看下zk集群的特点。
顺序一致性
客户端的更新顺序与它们被发送的顺序相一致。
原子性
更新操作要么成功要么失败,没有第三种结果。
单一视图
无论客户端连接到哪一个服务器,客户端将看到相同的 ZooKeeper 视图。
可靠性
一旦一个更新操作被应用,那么在客户端再次更新它之前,它的值将不会改变。
实时性
连接上一个服务端数据修改,所以其他的服务端都会实时的跟新,不算完全的实时,有一点延时的
角色轮换避免单点故障
当leader出现问题的时候,会选举从follower中选举一个新的leader
集群中的角色
Leader 集群工作机制中的核心
事务请求的唯一调度和处理者,保证集群事务处理的顺序性
集群内部个服务器的调度者(管理follower,数据同步)
Follower 集群工作机制中的跟随者
处理非事务请求,转发事务请求给Leader
参与事务请求proposal投票
参与leader选举投票
lObserver 观察者
3.30以上版本提供,和follower功能相同,但不参与任何形式投票
处理非事务请求,转发事务请求给Leader
提高集群非事务处理能力
Zookeeper集群一致性协议ZAB解析
zab协议解决的问题和paxos一样,是解决分布式系统的数据一致性问题
zookeeper就是根据zab协议建立了主备模型完成集群的数据同步(保证数据的一致性),前面介绍了集群的各种角色,这说所说的主备架构模型指的是,在zookeeper集群中,只有一台leader(主节点)负责处理外部客户端的事务请求(写操作),leader节点负责将客户端的写操作数据同步到所有的follower节点中。
zab协议核心是在整个zookeeper集群中只有一个节点既leader将所有客户端的写操作转化为事务(提议proposal).leader节点再数据写完之后,将向所有的follower节点发送数据广播请求(数据复制),等所有的follower节点的反馈,在zab协议中,只要超过半数follower节点反馈ok,leader节点会向所有follower服务器发送commit消息,既将leader节点上的数据同步到follower节点之上。
发现,整个流程其实和paxos协议其实大同小异。说zab是paxos的一种实现方式其实并不过分。
Zab再细看可以分成两部分。第一的消息广播模式,第二是崩溃恢复模式。
正常情况下当客户端对zk有写的数据请求时,leader节点会把数据同步到follower节点,这个过程其实就是消息的广播模式
在新启动的时候,或者leader节点奔溃的时候会要选举新的leader,选好新的leader之后会进行一次数据同步操作,整个过程就是奔溃恢复。
消息广播模式
为了保证分区容错性,zookeeper是要让每个节点副本必须是一致的
- 在zookeeper集群中数据副本的传递策略就是采用的广播模式
- Zab协议中的leader等待follower的ack反馈,只要半数以上的follower成功反馈就好,不需要收到全部的follower反馈。
zookeeper中消息广播的具体步骤如下:
1. 客户端发起一个写操作请求
2. Leader服务器将客户端的request请求转化为事物proposql提案,同时为每个proposal分配一个全局唯一的ID,即ZXID。
3. leader服务器与每个follower之间都有一个队列,leader将消息发送到该队列
4. follower机器从队列中取出消息处理完(写入本地事物日志中)毕后,向leader服务器发送ACK确认。
5. leader服务器收到半数以上的follower的ACK后,即认为可以发送commit
6. leader向所有的follower服务器发送commit消息。
zookeeper采用ZAB协议的核心就是只要有一台服务器提交了proposal,就要确保所有的服务器最终都能正确提交proposal。这也是CAP/BASE最终实现一致性的一个体现。
回顾一下:前面还讲了2pc协议,也就是两阶段提交,发现流程2pc和zab还是挺像的,
zookeeper中数据副本的同步方式与二阶段提交相似但是却又不同。二阶段提交的要求协调者必须等到所有的参与者全部反馈ACK确认消息后,再发送commit消息。要求所有的参与者要么全部成功要么全部失败。二阶段提交会产生严重阻塞问题,但paxos和2pc没有这要求。
为了进一步防止阻塞,leader服务器与每个follower之间都有一个单独的队列进行收发消息,使用队列消息可以做到异步解耦。leader和follower之间只要往队列中发送了消息即可。如果使用同步方式容易引起阻塞。性能上要下降很多
崩溃恢复
背景(什么情况下会崩溃恢复)
zookeeper集群中为保证任何所有进程能够有序的顺序执行,只能是leader服务器接受写请求,即使是follower服务器接受到客户端的请求,也会转发到leader服务器进行处理。
如果leader服务器发生崩溃(重启是一种特殊的奔溃,这时候也没leader),则zab协议要求zookeeper集群进行崩溃恢复和leader服务器选举。
最终目的(恢复成什么样)
ZAB协议崩溃恢复要求满足如下2个要求:
确保已经被leader提交的proposal必须最终被所有的follower服务器提交。
确保丢弃已经被leader出的但是没有被提交的proposal。
新选举出来的leader不能包含未提交的proposal,即新选举的leader必须都是已经提交了的proposal的follower服务器节点。同时,新选举的leader节点中含有最高的ZXID。这样做的好处就是可以避免了leader服务器检查proposal的提交和丢弃工作。
l每个Server会发出一个投票,第一次都是投自己。投票信息:(myid,ZXID)
收集来自各个服务器的投票
l处理投票并重新投票,处理逻辑:优先比较ZXID,然后比较myid
统计投票,只要超过半数的机器接收到同样的投票信息,就可以确定leader
改变服务器状态
为什么优先选大的zxid? 最后一个发出提交任务的结点,拥有最全的事务信息。
典型应用场景
数据发布与订阅(配置中心)
集群管理(服务注册于发现)
分布式锁
基于同名节点的分布式锁