资料参考来源拉勾Java高薪训练营
1、简介
1.1、服务之间的通信方式
- 通过网络进行信息共享
- 通过共享存储
ZooKeeper使用共享存储的方式。大多数分布式系统出现的问题,都源于信息共享出现问题,Zookeeper解决协同问题的关键是保证分布式系统信息的一致性
1.2、Zookeeper基本概念
1. 集群角色
Zookeeper有Leader、Follower、Observer三种角色,Zookeeper中通过Leader选举来选定一台被称为Leader的机器,Leader提供读写服务,Follower和Observer只提供读服务,但是Observer不参与Leader选举和写操作过半投票策略。Observer在不影响写性能的情况下提高集群性能。
2. 会话
会话是客户端和Zookeeper的一个TCP长连接会话,通过心跳检测来保持有效的会话。
3. 节点(Znode)
Zookeeper中数据存储在内存中,数据模型是一棵树,有斜杠(/)进行分割的路径,比如 /app/test,每个Znode上都会保存自己的数据内容和一系列的属性信息。
- 节点分类
节点类型分为持久性节点(Persistent)、临时性节点(Ephemeral)、顺序性节点(Sequential),组合成以下四种节点类型:
类型 | 说明 |
持久节点 | 被创建后一直存在服务器上,直到删除操作主动清除 |
持久顺序节点 | 特性和持久节点一致,额外加上了顺序,在创建时,会在节点名后面加上一个数字后缀,来表示顺序 |
临时节点 | 生命周期和客户端会话绑定在一起,客户端会话结束,节点会被自动删除。临时节点不能创建子节点 |
临时顺序节点 | 和临时节点特性一 致 ,创建节点时在节点名加上了数字后缀来表示顺序 |
- 节点的状态信息
节点 | 含义 |
cZxid | Create ZXID,表示节点被创建时的事务ID |
ctime | Create Time,表示节点创建时间 |
mZxid | Modified ZXID,表示节点最后一次被修改时的事务ID |
mtime | Modified Time,表示节点最后一次被修改的时间 |
pZxid | 该节点的子节点列表最后一次被修改时的事务ID。只有子节点列表变更才会更新 pZxid,子节点内容变更不会更新 |
cversion | 表示子节点的版本号 |
dataVersion | 表示内容版本号 |
aclVersion | 标识acl版本 |
ephemeralOwner | 表示创建该临时节点时的会话 sessionID,如果是持久性节点那么值为0 |
dataLength | 表示数据长度 |
numChildren | 表示直系子节点数 |
4. 版本(version)
zookeeper会在节点上存储数据,同时会有一个叫Stat的数据结构,记录了Znode的版本信息。Stat记录了这个ZNode的三个数据版本,分别是version(当前ZNode的版本)、cversion(当前ZNode子节点的版本)、aversion(当前ZNode的ACL版本),基于版本来操作数据。
5. Watcher(事件监听器)
Watcher是Zookeeper中很重要的特性,Zookeeper允许客户端在指定节点上注册一些Watcher,并在一些特殊事件触发的时候,通知这个客户端,该机制是Zookeeper实现分布式协调服务的重要特性。watcher的工作流程如下:
6. ACL(Access Control Lists)
ACL机制:权限模式(Scheme)、授权对象(ID)、权限(Permission),通常使用"scheme: id : permission"来标识一个有效的ACL信息。
(1) 权限模式:Scheme
模式 | 使用范围 | 使用举例 | 说明 |
IP | ip:192.168.0.110 | 表示权限控制针对该IP地址 | |
ip:192.168.0.1/24 | 表示针对192.168.0.*这个网段进行权限控制 | ||
Digest | 最常用 | username:password | Zookeeper会先后对其进行SHA-1加密和BASE64编码 |
World | 最开放 | world:anyone | 所有用户都可以在不进行任何权限校验的情况下操作 |
Super | 超级用户 | 超级用户可以对任意ZooKeeper上的数据节点进行任何操作 |
(2) 授权对象:ID
根据不同模式,确定不同的ID
(3) 权限,定义了5种权限:
权限 | 说明 |
CREATE | 创建子节点的权限 |
READ | 获取节点数据和子节点列表的权限 |
WRITE | 更新节点的权限 |
DELETE | 删除子节点的权限 |
ADMIN | 设置节点ACL的权限 |
2、Zookeeper环境搭建
2.1、单机模式
1.下载
2.上传
3.解压:tar -zxvf zookeeper-3.4.14.tar.gz
4.进入 zookeeper-3.4.14目录,创建 data 文件夹
cd zookeeper-3.4.14
mkdir data
5、修改配置文件名称
cd conf
mv zoo_sample.cfg zoo.cfg
6、修改zoo.cfg中的data属性
dataDir=/root/zookeeper-3.4.14/data
7、zookeeper服务启动
进入bin目录,启动服务输入命令
./zkServer.sh start
关闭服务
./zkServer.sh stop
查看状态
./zkServer.sh status
2.2、伪集群模式
单机模拟集群模式 Zookeeper的运行,也就是将不同实例运行在同一台机器,用端口进行区分。搭建步骤如下:
1.下载
2.上传
3.解压
(1) 创建目录zkcluster
mkdir zkcluster
(2) 解压三份到zkcluster下
tar -zxvf zookeeper-3.4.14.tar.gz -C /zkcluster
(3) 并分别命名zookeeper01,zookeeper02,zookeeper03
mv zookeeper-3.4.14 zookeeper01
4.分别在zookeeper01、zookeeper02、zookeeper03⽬录下创建data及logs目录
mkdir data
cd data
mkdir logs
5.修改配置文件名称
cd conf
mv zoo_sample.cfg zoo.cfg
6.配置每一个Zookeeper 的dataDir(zoo.cfg) clientPort 分别为2181 2182 2183
clientPort=2181
dataDir=/zkcluster/zookeeper01/data
dataLogDir=/zkcluster/zookeeper01/data/logs
7.配置集群
(1) 在每个zookeeper的 data目录下创建一个 myid 文件,内容分别是1、2、3 。这个文件就是记录每个服务器的ID
touch myid
(2) 在每一个zookeeper的 zoo.cfg配置客户端访问端口(clientPort)和集群服务器IP列表。
server.1=10.211.55.4:2881:3881
server.2=10.211.55.4:2882:3882
server.3=10.211.55.4:2883:3883
#server.服务器ID=服务器IP:服务器之间通信端口:服务器之间投票选举端口
8.启动集群
依次启动三个zk实例
3、Zookeeper命令行操作
进⼊到zookeeper的bin⽬录之后,通过zkClient进⼊zookeeper客户端命令⾏
客户端连接Zookeeper:
./zkcli.sh 连接本地的zookeeper服务
./zkCli.sh -server ip:port 连接执行服务器
创建节点:
create [-s][-e] path data acl
其中 -s或-e分别指节点特性,-s是顺序节点,-e是临时节点,若不指定,则创建持久节点。acl用来进行权限控制。永久节点不同于顺序节点,不会⾃动在后⾯添加⼀串数字。
读取节点:
ls path
查看指定路径下的子节点列表
get path
获取指定路径节点的数据
更新节点:
set path data [version]
可以指定版本更新节点数据
删除节点:
delete path [version]
若删除节点存在子节点,那么无法删除该节点,必须先删除子节点,再删除父节点
4、Zookeeper应用场景
4.1、数据发布订阅
其实就是配置中心,发布者发布数据到Zookeeper上的节点,通过Watcher通知订阅者来获取数据,实现配置信息的集中式管理和数据的动态更新。
比如一个数据库配置信息jdbc.properties信息可以存储到一个节点上,集群中的机器启动时读取这个配置信息同时注册一个数据变更的Watcher监听,一旦数据发生变更,所有订阅的客户端机器都会收到通知,然后就可以重新去获取最新的配置信息。
4.2、命名服务
命名服务其实最主要的就是需要给服务生成一个全局唯一的名字,类似数据库主键。通过Zookeeper在创建节点时,可以创建顺序节点,Zookeeper就会自动在节点后面加上一个序号,这个节点的名称就是全局唯一的。
4.3、集群管理
集群管理中比如集群监控,监控系统对Zookeeper的数据节点注册Watcher监听,当每台服务器在Zookeeper注册一个临时节点时,监控系统就能收到通知新增了机器。当集群中某台机器宕机或者下线,对应的临时节点就会被删除,监控系统也能收到对应的Watcher事件通知。
4.4、Master选举
最简单的就是所有需要参与Master选举的机器同时向Zookeeper中同一个路径下创建一个名称相同的临时节点,谁创建成功了,谁就是Master。当Master宕机时,临时节点就会被删除,同时通过Watcher通知集群其他机器,重新选举Master。
4.5、分布式锁
排他锁:和Master选举差不多,都去创建节点,谁能创建成功谁就能获取到锁。没有获取到锁的客户端,注册Watcher监听,当获取到锁的客户端宕机或者执行完业务逻辑主动删除这个临时节点时,Watcher通知其他客户端再来竞争锁。
共享锁:如果事务T1对数据对象O1加上了共享锁,那么当前事务只能对O1进行读取操作,其他事务也只能对这个数据对象加共享锁——直到该数据对象上的所有共享锁都被释放。共享锁和排他锁最根本的区别在于,加上排他锁后,数据对象只对一个事务可见,加上共享锁后,数据对所有事务都可见。所有客户端在Zookeeper创建临时顺序节点,判断自己是否是序号最小的,如果不是最小的,需要等待,同时向比自己小的最后一个节点注册Watcher监听。等收到Watcher监听后重复上面的步骤。
4.6、分布式队列
- FIFO先进先出
1. 通过调用getChildren接口来获取/queue_fifo节点的所有子节点,即获取队列中所有的元素。
2. 确定自己的节点序号在所有子节点中的顺序。
3. 如果自己的序号不是最小,那么需要等待,同时向比自己序号小的最后一个节点注册Watcher监听
4. 接收到Watcher通知后,重复步骤1。
- Barrier:分布式屏障
1. 通过调用getData接口获取/queue_barrier节点的数据内容:10。
2. 通过调用getChildren接口获取/queue_barrier节点下的所有子节点,同时注册对子节点变更的 Watcher监听。
3. 统计子节点的个数。
4. 如果子节点个数还不足10个,那么需要等待。
5. 接受到Wacher通知后,重复步骤2
5、深入
5.1、ZAB协议
Zookeeper使用的是ZAB协议来作为其数据一致性的核心算法,ZAB是专门为Zookeeper设计的一种支持崩溃恢复的原子广播协议。
ZAB的核心是定义了对于那些会改变Zookeeper服务器数据状态的事务请求的处理方式:
所有事务都必须由一个全局唯一的服务器来协调处理,这样的服务器叫Leader服务器,余下的服务器器称为Follower服务器,Leader服务器负责将客户端事务请求转化成一个事务Proposal(提议),然后发送给所有的Follower服务器,等待超过半数的Follower服务器进行了正确的反馈过后,Leader再次向所有的Follower服务器发起commit消息,进行事务的提交。
ZAB协议包括两种基本模式:
崩溃恢复模式:当服务器启动过程中,或者Leader服务器出现网络异常、崩溃推出或重启等情况,ZAB协议就会进入到崩溃恢复模式,同时选举出新的Leader服务器。当选举出新的Leader服务器,同时集群中已经有过半的机器与Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式。
消息广播模式:当集群中已经有过半的服务器与Leader完成状态同步后,那么就进入到消息广播模式。Zookeeper只允许一个Leader服务器来进行事务处理,就算客户端请求到一个Follower服务器,这个Follower会判断是否是事务请求,也就是写请求,如果是事务请求,那么会把这个请求转发到Leader服务器来处理。Leader服务器接收到请求后,会生成对应的事务提议并发起一轮广播协议。
- ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器提交
- ZAB协议需要确保丢弃那么只在Leader服务器上被提出但没提交的事务
5.2、服务器角色
5.2.1、Leader
Leader服务器是Zookeeper集群工作的核心,主要负责:
- 事务请求的唯一调度者,保证集群事务处理的顺序性。
- 集群内部各个服务器的调度者。
请求处理链:
PrepRequestProcessor。请求预处理器,识别当前请求是否是事务请求,对于事务请求,PrepRequestProcessor会对其进行一系列的预处理,比如创建请求事务头、事务体、会话检查、ACL检查、版本检查等。
ProposalRequestProcessor。事务投票处理器,Leader服务器事务处理流程的发起者,对于非事务请求,ProposalRequestProcessor会将请求转发到CommitProcessor处理器,不再做其他处理。而对于事务请求,处理转发到CommitProcessor外,还会根据请请求类型创建对应的Proposal提议,并发送给所有Follower服务器来发起一起集群内事务投票。同时还会将事务请求转发到SyncRequestProcessor进行事务日志的记录。
SyncRequestProcessor。事务日志记录处理器。
AckRequestProcessor。负责在SyncRequestProcessor完成事务日志记录后,向Proposal的投票收集器发送ACK反馈。
CommitProcessor。事务提交处理器,对于非事务请求,直接转发给下一个处理器,对于事务请求,需要等待Proposal投票,知道Proposal可以被提交。
ToBeCommitProcessor。该处理器有一个toBeApplied队列,存储已经被CommitProcessor处理过的可被提交的Proposal。会将请求交付给FinalRequestProcessor处理,处理完成后移出队列。
FinalRequestProcessor。用来进行客户端请求返回之前的操作,包括创建客户端请求响应,针对事务,该处理器还会负责将事务应用到内存数据库中。
5.2.2、Follower
Follower作为Zookeeper集群状态中的跟随者,主要负责:
- 处理客户端非事务请求(读请求),转发事务请求给Leader服务器
- 参与事务请求Proposal的投票
- 参与Leader选举
请求处理链:
FollowerRequestProcessor。其作用是识别当前请求是否是事务请求,如果是,那么会转发给Leader服务器。
SendAckRequestProcessor。事务日志反馈功能,在完成事务日志记录后,向Leader服务器发送ACK消息以表明⾃身完成了事务⽇志的记录⼯作
5.2.3、Observer
Observer是Zookeeper从3.0版本开始引入的服务器角色,工作原理和Follower基本一致,只是不参与事务请求Proposal的投票和Leader选举,主要是用于在不影响集群事务处理能力的前提下提升集群的非事务处理能力。
请求处理链:
5.3、服务器启动流程
Zookeeper服务器的启动,大致可以分为以下五个步骤:
配置文件解析
初始化数据管理器
初始化网络IO管理器
数据恢复
对外服务
单机版服务器启动流程:
集群版服务器启动流程:
Leader和Follower在启动期间的交互流程如图: