文章目录
zookeeper学习
1.简介
官网地址:https://zookeeper.apache.org/
Apache ZooKeeper致力于开发和维护一个开源服务器,实现高度可靠的分布式协调
1.1业务场景
zookeeper是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能,且具有严格顺序访问控制能力的分布式协调存储服务
- 维护配置信息
通过zab
协议保证一致性,通过watch监听机制从配置中心拉去最新的配置信息 - 分布式锁服务
通过临时有序节点实现 - 集群管理
当某个服务宕机或者加入集群中,zookeeper将变化状态以事件方式推送给集群,通过watch机制实现 - 生成分布式唯一ID
在分库分表环境中不能使用自增id来表示唯一id,通过zookeeper创建持久顺序节点,返回该节点序号,即为新id,然后将比自己小的节点删除
1.2设计目标
zooKeeper
致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务
- 高性能
zookeeper
将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,尤其用于以读为主的应用场景 - 高可用
zookeeper
一般以集群的方式对外提供服务,一般3~5
台机器就可以组成一个可用的Zookeeper
集群了,每台机器都会在内存中维护当前的服务器状态,井且每台机器之间都相互保持着通信。只要集群中超过一半的机器都能够正常工作,那么整个集群就能够正常对外服务 - 严格顺序访问
对于来自客户端的每个更新请求,Zookeeper
都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序
1.3 zookeeper的数据模型
zookeeper
的数据节点可以视为树状结构(或目录),树中的各个节点被称为znode
(即zookeeper node
),一个znode
可以由多个子节点。zookeeper
节点在结构上表现为树状;
znode
,具有文件和目录两种特点,即像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分个。
znode
大体上分为3
个部分:
- 节点的数据:即
znode data
(节点路径path
,节点data
)的关系就像是Java map
中的key value
关系 - 节点的子节点
children
- 节点的状态
stat
:用来描述当前节点的创建、修改记录,包括cZxid
、ctime
等
1.3.1节点状态stat的属性
在`zookeeper shell `中使用 `get -s`命令查看指定路径节点的`data`、`stat`信息。
属性说明:
节点的各个属性如下。其中重要的概念是Zxid(Zookeeper Transaction ID)
,Zookeeper
节点的每一次更改都具有唯一的Zxid
,如果Zxid-1
小于 Zxid-2
,则Zxid-1
的更改发生在 Zxid-2
更改之前
https://zookeeper.apache.org/doc/r3.4.14/zookeeperProgrammers.html#sc_zkDataModel_znodes
cZxid
数据节点创建时的事务ID——针对于zookeeper
数据节点的管理:我们对节点数据的一些写操作都会导致zookeeper
自动地为我们去开启一个事务,并且自动地去为每一个事务维护一个事务ID
ctime
数据节点创建时的时间mZxid
数据节点最后一次更新时的事务IDmtime
数据节点最后一次更新时的时间pZxid
数据节点最后一次修改此znode
子节点更改的zxid
cversion
子节点的更改次数dataVersion
节点数据的更改次数aclVersion
节点的ACL更改次数——类似linux
的权限列表,维护的是当前节点的权限列表被修改的次数ephemeralOwner
如果节点是临时节点,则表示创建该节点的会话的SessionID
;如果是持久节点,该属性值为0dataLength
数据内容的长度numChildren
数据节点当前的子节点个数
1.3.2节点类型
节点类型:
- PERSISTENT 持久类型,如果不手动删除 一直存在 不指定类型时 默认为持久类型
- PERSISTENT_SEQUENTIAL 有序 自增
- EPHEMERAL 临时 客户端session失效就会删除节点 没有子节点
- EPHEMERAL_SEQUENTIAL 有序 自增
2.重要概念
2.1节点类型
2.2acl权限控制
https://zookeeper.apache.org/doc/r3.4.14/zookeeperProgrammers.html#sc_ZooKeeperAccessControl
zookeeper
类似文件系统,client
可以创建节点、更新节点、删除节点,那么如何做到节点的权限控制呢?
zookeeper
的 access control list
访问控制列表可以做到这一点
acl
权限控制,使用scheme:id:permission
来标识,主要涵盖3个方面:
https://zookeeper.apache.org/doc/r3.4.14/zookeeperProgrammers.html#sc_BuiltinACLSchemes
- 权限模式(
scheme
):授权的策略 - 授权对象(
id
):授权的对象 - 权限(
permission
):授予的权限
其特性如下:
-
zookeeper
的权限控制是基于每个znode
节点的,需要对每个节点设置权限 -
每个
znode
支持多种权限控制方案和多个权限 -
子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点
权限模式
采用何种方式授权
方案 | 描述 |
---|---|
world | 只有一个用户:anyone ,代表登录zookeeper 所有人(默认) |
ip | 对客户端使用IP地址认证 |
auth | 使用已添加认证的用户认证 |
digest | 使用"用户名:密码"方式认证 |
授权对象
- 给谁授予权限
- 授权对象ID是指,权限赋予的实体,例如:IP地址或用户
授权的权限
-
授予什么权限
-
create、delete、read、writer、admin
也就是 增、删、查、改、管理权限,这5种权限简写为 c d r w a,注意:
这五种权限中,有的权限并不是对节点自身操作的例如:delete是指对子节点的删除权限可以试图删除父节点,但是子节点必须删除干净,所以
delete
的权限也是很有用的
权限 | ACL简写 | 描述 |
---|---|---|
create | c | 可以创建子节点 |
delete | d | 可以删除子节点(仅下一级节点) |
read | r | 可以读取节点数据以及显示子节点列表 |
write | w | 可以设置节点数据 |
admin | a | 可以设置节点访问控制权限列表 |
授权的相关命令
命令 | 使用方式 | 描述 |
---|---|---|
getAcl | getAcl | 读取ACL权限 |
setAcl | setAcl | 设置ACL权限 |
addauth | addauth | 添加认证用户 |
world权限模式
默认节点权限为
设置节点权限
node2节点权限被改为 drwa 去掉create的权限,然后在给node2创建节点 权限不足
ip模式
./zkServer.sh -server 192.168.1.102
可以远程登录
setAcl /node1 ip:192.168.1.103:drwa
- 如果在两台不同的虚拟机中,另一台用远程连接的模式,进行上面这条命令,那么只会有一台被授权
- 需要两台虚拟机一起授权的话需要用逗号将授权列表隔开:
setAcl /hadoop ip:192.168.1.103:cdrwa,ip:192.168.1.102:cdrwa
auth认证用户模式
addauth digest <user>:<password>
setAcl <path> auth:<user>:<acl>
-
create /hadoop "hadoop" # 初始化测试用的节点 addauth digest itcast:123456 # 添加认证用户 setAcl /hadoop auth:itcast:cdrwa # 设置认证用户 quit # 退出后再./zkCli.sh 进入 get /hadoop # 这个时候就没有权限了,需要再次认证 addauth digest itcast:123456 # 认证,密码错了的话 zookeeper 不会报错,但是不能认证 get /hadoop
Digest授权模式
setAcl <path> digest:<user>:<password>:<acl>
-
这里的密码是经过
SHA1
以及BASE64
处理的密文,在shell 中可以通过以下命令计算:-
echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
-
# 计算密码 echo -n itcast:12345 | openssl dgst -binary -sha1 | openssl base64 # 获取密码,设置权限列表 setAcl /hadoop digest:itcast:qUFSHxJjItUW/93UHFXFVGlvryY=:cdrwa # 现在想要get /hadoop 需要登录了 addauth digest itcast:12345 get /hadoop
-
多种授权模式
仅需逗号隔开
-
setAcl /hadoop ip:192.168.133.132:cdrwa,auth:hadoop:cdrwa,digest:itcast:673OfZhUE8JEFMcu0l64qI8e5ek=:cdrwa
acl 超级管理员
zookeeper
的权限管理模式有一种叫做super
,该模式提供一个超管,可以方便的访问任何权限的节点
假设这个超管是supper:admin
,需要为超管生产密码的密文
echo -n super:admin | openssl dgst -binary -sha1 | openssl base64
- 那么打开
zookeeper
目录下/bin/zkServer.sh
服务器脚本文件,找到如下一行:
/nohup # 快速查找,可以看到如下
nohup "$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}"
- 这个就算脚本中启动
zookeeper
的命令,默认只有以上两个配置项,我们需要添加一个超管的配置项
"-Dzookeeper.DigestAuthenticationProvider.superDigest=super:xQJmxLMiHGwaqBvst5y6rkB6HQs="
- 修改后命令变成如下
nohup "$JAVA" "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" "-Dzookeeper.DigestAuthenticationProvider.superDigest=super:xQJmxLMiHGwaqBvst5y6rkB6HQs="
# 重起后,现在随便对任意节点添加权限限制
setAcl /hadoop ip:192.168.1.1:cdrwa # 这个ip并非本机
# 现在当前用户没有权限了
getAcl /hadoop
# 登录超管
addauth digest super:admin
# 强行操作节点
get /hadoop
2.3监听机制
2.3.1官网描述
https://zookeeper.apache.org/doc/r3.4.14/zookeeperProgrammers.html#Java+Binding
大致意思是:zookeeper所有读取操作都可以为节点设置watche,在watches的定义中需要考虑以下三个关键点:
- 一次性触发:数据更改后,一个监视事件将发送到客户端。如果该节点再次更改则不会触发监听事件除非重新设置监听事件
- 发送到客户端:ZooKeeper提供了订购保证:客户端在第一次看到监视事件之前,将永远不会看到为其设置了监视的更改。
- 给节点设置子节点监听
2.3.2 watcher架构
watcher
实现由三个部分组成
zookeeper
服务端zookeeper
客户端- 客户端的
ZKWatchManager对象
客户端首先将 Watcher
注册到服务端,同时将 Watcher
对象保存到客户端的watch
管理器中。当Zookeeper
服务端监听的数据状态发生变化时,服务端会主动通知客户端,接着客户端的 Watch
管理器会**触发相关 Watcher
**来回调相应处理逻辑,从而完成整体的数据 发布/订阅
流程
2.3.3 watcher特性
特性 | 说明 |
---|---|
一次性 | watcher 是一次性的,一旦被触发就会移除,再次使用时需要重新注册 |
客户端顺序回调 | watcher 回调是顺序串行执行的,只有回调后客户端才能看到最新的数据状态。一个watcher 回调逻辑不应该太多,以免影响别的watcher 执行 |
轻量级 | WatchEvent 是最小的通信单位,结构上只包含通知状态、事件类型和节点路径,并不会告诉数据节点变化前后的具体内容 |
时效性 | watcher 只有在当前session 彻底失效时才会无效,若在session 有效期内快速重连成功,则watcher 依然存在,仍可接收到通知; |
watcher接口设计
Watcher
是一个接口,任何实现了Watcher
接口的类就算一个新的Watcher
。Watcher
内部包含了两个枚举类:KeeperState
、EventType
Watcher通知状态(KeeperState)
KeeperState
是客户端与服务端连接状态发生变化时对应的通知类型。路径为org.apache.zookeeper.Watcher.EventKeeperState
,是一个枚举类,其枚举属性如下:
枚举属性 | 说明 |
---|---|
SyncConnected | 客户端与服务器正常连接时 |
Disconnected | 客户端与服务器断开连接时 |
Expired | 会话session 失效时 |
AuthFailed | 身份认证失败时 |
Watcher事件类型(EventType)
EventType
是数据节点znode
发生变化时对应的通知类型。EventType
变化时KeeperState
永远处于SyncConnected
通知状态下;当keeperState
发生变化时,EventType
永远为None
。其路径为org.apache.zookeeper.Watcher.Event.EventType
,是一个枚举类,枚举属性如下:
枚举属性 | 说明 |
---|---|
None | 无 |
NodeCreated | Watcher 监听的数据节点被创建时 |
NodeDeleted | Watcher 监听的数据节点被删除时 |
NodeDataChanged | Watcher 监听的数据节点内容发生更改时(无论数据是否真的变化) |
NodeChildrenChanged | Watcher 监听的数据节点的子节点列表发生变更时 |
3.搭建及使用
3.1单机安装
前提:需要安装jdk环境
步骤:
- 下载
官网下载 https://downloads.apache.org/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz
或者直接在centos7 使用wget命令下载
wget https://downloads.apache.org/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz - 下载完成后进行解压
tar -zvxf apache-zookeeper-3.6.3-bin.tar.gz - 复制配置文件
到zookeeper下修改配置文件
----- cd /usr/local/zookeeper/conf
----- mv zoo_sample.cfg zoo.cfg
修改 zoo.cfg 配置文件,将 dataDir=/tmp/zookeeper 修改为指定的data目录 尽量不要在tmp目录下。 - 启动测试
启动:bin目录下 ./zkServer.sh start
检验:zkServer.sh status
连接:./bin/zkCli.sh
3.2常用shell命令
- ls:查看某个目录包含的所有文件
ls [-s] [-w] [-R] path
[-s] : 查看某一节点下的子节点加当前节点的元信息,相当于之前版本的ls2命令。
[-w] :查看节点并为节点添加一个监听,当节点被修改时,该客户端会收到一个回调。之前版本是 在path 后面加一个watch实现:ls path watch 。
[-R]: 返回当前节点路径,当前节点的子节点,当前节点的子节点的子节点(递归)。 - ls2:和ls一样 只是多了时间和版本信息
create:创建znode 并设置初始内容
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
[-s] : 创建有序节点。
[-e] : 创建临时节点。
[-c] : 创建一个容器节点。
[t ttl] : 创建一个TTL节点, -t 时间(单位毫秒)。
path: 路径 ,因为没有中括号,所以是必须参数。
[data]:节点的数据,可选,如果不使用时,节点数据就为null。
[acl] :设置权限 - get:获取znode的数据
get [-s] [-w] path
[-s] :查看节点数据加元信息。
[-w] : 查看节点并为节点添加一个监听,当节点被修改时,该客户端会收到一个回调。 - set:修改znode内容
set [-s] [-v version] path data
[-s] :返回修改后节点的元信息。
[-v version] :指定数据的版本,版本不符合时修改失败,类似关系型数据库的乐观锁。
path :修改节点路径。
data :修改的数据。 - delete:删除znode
- quit:退出客户端
- help:帮助命令
- deleteall:递归删除
deleteall path - history 查看该客户端登录以来使用的最进执行的11个命令。
redo cmdno //再执行一次指定的历史命令。cmdno 是执行history命令时显示命令左边的index。
connect host:port 连接其他Zookeeper服务器。
printwatches on|off 是否开启watch机制,如果设置为off,则该客户端监听的节点事件都不会生效、默认on。 - removewatches path 删除在某节点上设置的监听。
- sync path 把当前Zookeeper服务器的指定节点同步到主从集群中的其他Zookeeper服务器上。
3.3 集群搭建
zoo.cfg详解:
- tickTime: 基本事件单元,以毫秒为单位。这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每隔 tickTime时间就会发送一个心跳。
- dataDir: 存储内存中数据库快照的位置,顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
- clientPort: 这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
- initLimit: 这个配置项是用来配置 Zookeeper 接受客户端初始化连接时最长能承受多少个心跳时间间隔数,当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒。
- syncLimit: 这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,
最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 5*2000=10 秒 - server.A = B:C:D :
A表示这个是第几号服务器,
B 是这个服务器的 ip 地址;
C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;
D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader
集群角色:
- Leader:作为整个zookeeper集群的主节点,负责响应所有对zookeeper状态变更的请求。它会将每个状态跟新请求进行排序和编号,以便保证整个集群内部消息处理的FIFO,写操作都走leader
- Follower: 除了响应本服务器上的读请求外,follower还要处理learder的提议,并在leader提交该提议时在本地也进行提交。follower参与新的leader的选举
- Observer:如果zookeeper集群的读取负载很高,或者客户端多到跨机房,可以设置一些observer服务器,以提高读取的吞吐量。observer和follower比较相似,只有一些小区别:首先observer不属于法定人数,即不参加选举投票也不响应提议;其次是observer不需要将事务持久化到磁盘,一旦observer被重启,需要从leader重新同步这个名字空间。
前置准备:
- 需要安装jdk环境
- 准备三个centos7虚拟机 本次案例三个虚拟机ip为:192.168.3.102、192.168.3.103、192.168.3.104
搭建步骤
1.下载上传zookeeper压缩包到centos7
2.解压 tar zookeeper-3.6.2.tar.gz
3.配置环境变量:
vim /etc/profile
#在配置文件中添加zookeeper的环境变量
export ZOOKEEPER_HOME=/usr/local/zookeeper/zookeeper3.6.2 #zookeeper的安装路径
export PATH=$JAVA_HOME/bin:$ZOOKEEPER_HOME/bin:$PATH
#刷新:
source /etc/profile
4.到zookeeper下修改配置文件
cd /usr/local/zookeeper/zookeeper3.6.2/conf
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg #修改两处
dataDir=/usr/local/zookeeper/zookeeper3.6.2/data
最后面添加
server.1=192.168.3.102:2888:3888
server.2=192.168.3.103:2888:3888
server.3=192.168.3.104:2888:3888
在/usr/local/zookeeper/zookeeper3.6.2/路径下(zookeeper的安装路径) 创建data文件夹用来存储数据mkdir data
5.虚拟机标识配置
在创建的data下创建文件myid并填写内容为:
第一个zookeeper节点为1,第二个节点为2,第三个节点为3
对应着:
server.1=192.168.3.102:2888:3888
server.2=192.168.3.103:2888:3888
server.3=192.168.3.104:2888:3888
即
192.168.3.102 的myid 为1
192.168.3.103 的myid 为2
192.168.3.104 的myid 为3
注意:标识符不要写错 否则集群启动会报错
6.启动zookeeper:
cd /usr/local/zookeeper/bin
./zkServer.sh start #(注意这里3台机器都要进行启动)
#查看状态(在三个节点上检验zk的mode,一个leader和俩个follower)
zkServer.sh status
可以看到01 02 为从节点 03 为主节点
7.连接集群测试
在192.168.3.102 从节点服务器上连接集群
bin/zkCli.sh -server 192.168.3.102:2181,192.168.3.103:2181,192.168.3.104:2181
create /node1 'lsx'
在192.168.3.104 主节点连接自己客户端
bin/zkCli.sh
可以获取到在集群模式下创建的节点 到此完成集群搭建
8.坑点:可以通过zkServer.sh start-foreground
排查
1.端口号被占用
杀掉占用的进程
2.myid创建不对 没有在指定目录下创建 或者 设置的value值不对
回到4 5步骤重新搭建
3.防火墙导致集群之间端口监听失败,通过systemctl stop firewalld.service
关闭防火墙