老板说我不懂Zookeeper分布式协调,他看完这个直接服了
昨天老板气呼呼跑到我面前问我是不是根本不懂Zookeeper分布式协调,当时气不打一出来奋笔疾书写下这篇小见解,直接让他无话可说 于是乎我今天在这里分享给大家,希望对我们各位码农们有所帮助。
官方的解释:
一个中心化的分布式协调框架,它主要是用来解决分布式应用中经常遇到的一些数据管理问题。
如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
“神马?数据管理,那不是数据库干的事情么”。如果你这么理解就对了,Zookeeper其实你暂时就可以理解为,它是一个基于内存的数据库。对于上述这些名词(统一命名服务,状态同步,集群管理,分布式应用配置项),不熟悉分布架构的同学可能会有点蒙,不过没关系,我会通过很多的案例给同学们解释清楚这些到底都是啥,以及它存在的意义。
在了解Zookeeper之前,需要对分布式相关知识有一定了解,如果有了解过可以直接忽略,什么是分布式系统呢?通常情况下,单个物理节点很容易达到性能,CPU计算或者内存容量,网络IO 的瓶颈,所以这个时候就需要多个物理节点来共同完成某项任务,一个分布式系统的本质是分布在不同网络或计算机上的程序组件,彼此通过信息传递来协同工作的系统,而Zookeeper正是一个分布式应用协调框架,在分布式系统架构中有广泛的应用场景。
先来看看Zookeeper 的两个核心概念:
1,Zookeeper 核心概念
2, 文件系统的数据模型
Zookeeper维护一个类似文件系统的数据模型
每个子目录项都被称作为 node(目录节点),和文件系统类似,我们能够自由的增加、删除node,在一个node下增加、删除子znode。
有6 种类型的znode:(3.5.x版本以前只有前面四种)
1)、PERSISTENT-持久化目录节点
客户端与zookeeper断开连接后,该节点依旧存在,只要不手动删除该节点,他将永远存在
2)、 PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点
客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
3)、EPHEMERAL-临时目录节点
客户端与zookeeper断开连接后,该节点被删除
4)、EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点
客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
5)、Container 节点(3.5.3 版本新增,如果Container节点下面没有子节点,则Container节点在未来会被Zookeeper自动清除,定时任务默认60s 检查一次)
6)、TTL 节点( 3.5.3 版本新增,默认禁用,只能通过系统配置 zookeeper.extendedTypesEnabled=true 开启,不稳定)
2, 事件监听机制
客户端注册监听它关心的任意节点,或者目录节点及递归子目录节点
1. 如果注册的是对某个节点的监听,则当这个节点被删除,或者被修改时,对应的客户端将被通知
2. 如果注册的是对某个目录的监听,则当这个目录有子节点被创建,或者有子节点被删除,对应的客户端将被通知
3. 如果注册的是对某个目录的递归子节点进行监听,则当这个目录下面的任意子节点有目录结构的变化(有子节点被创建,或被删除)或者根节点有数据变化时,对应的客户端将被通知。
注意:所有的通知都是一次性的,及无论是对节点还是对目录进行的监听,一旦触发,对应的监听即被移除。递归子节点,监听是对所有子节点的,所以,每个子节点下面的事件同样只会被触发一次。
看完上面两个特性,可能还是不知道怎么玩,那下面就一起来安装使用一下,体验一下
3,Zookeeper 安装及实操
Zookeeper的安装非常简单,它本身是使用的Java语言编写,所以只要装好jdk环境就可以了
如果使用的 3.5.x 及以上版本需要 jdk8环境,
首先用 java -version 检查jdk版本, 确认是 jdk 8 后就可以进行 zookeeper版本下载了
本次案例用 zookeeper 3.5.8 版本进行演示 ,
环境准备:OS :centos 7
1.下载安装zookeeper
进到任意目录, 如 cd /usr/local/zookeeper
1 , 执行如下脚本进行 下载, 解压,运行
a.下载
wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.8/apache-zookeeper-3.5.8-bin.tar.gz
b.解压
tar -zxvf apache-zookeeper-3.5.8-bin.tar.gz
c.运行
cd apache-zookeeper-3.5.8-bin
bin/zkServer.sh start conf/zoo_sample.cfg
2 , 连接使用:
bin/zkCli.sh -server ip:port
如果服务器和客户端都是在本机 可以直接运行 bin/zkCli.sh
3, 停掉服务
bin/zkServer.sh stop conf/zoo_sample.cfg
当然, 别急着停 ,接下来开始实操
zk的命令不多,也非常简单很好掌握,接下来一起实战吧
Zookeeper 客户端实操
输入命令 help 查看zookeeper所支持的所有命令
1). 创建zookeeper 节点命令
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
中括号为可选项,没有则默认创建持久化节点
-s: 顺序节点
-e: 临时节点
-c: 容器节点
-t: 可以给节点添加过期时间,默认禁用,需要通过系统参数启用
(-Dzookeeper.extendedTypesEnabled=true, znode.container.checkIntervalMs : (Java system property only) New in 3.5.1: The time interval in milliseconds for each check of candidate container and ttl nodes. Default is "60000".)
创建节点:
create /test-node some-data
如上,没有加任何可选参数,创建的就是持久化节点
查看节点数据:
get /test-node
修改节点数据
set /test-node some-data-changed
查看节点状态信息
stat /test-node
Stat: 字段含义
cZxid:创建znode的事务ID(Zxid的值)。
mZxid:最后修改znode的事务ID。
pZxid:最后添加或删除子节点的事务ID(子节点列表发生变化才会发生改变)。
ctime:znode创建时间。
mtime:znode最近修改时间。
dataVersion:znode的当前数据版本。
cversion:znode的子节点结果集版本(一个节点的子节点增加、删除都会影响这个版本)。
aclVersion:表示对此znode的acl版本。
ephemeralOwner:znode是临时znode时,表示znode所有者的 session ID。 如果znode不是临时znode,则该字段设置为零。
dataLength:znode数据字段的长度。
numChildren:znode的子znode的数量。
根据状态数据中的版本号有并发修改数据实现乐观锁的功能
比如: 客户端首先获取版本信息, get -s /node-test
/test-node 当前的数据版本是 1 , 这时客户端 用 set 命令修改数据的时候可以把版本号带上
如果在执行上面 set命令前, 有人修改了数据,zookeeper 会递增版本号, 这个时候,如果再用以前的版本号去修改,将会导致修改失败,报如下错误
创建子节点, 这里要注意,zookeeper是以节点组织数据的,没有相对路径这么一说,所以,所有的节点一定是以 / 开头。
create /test-node/test-sub-node
查看子节点信息,比如根节点下面的所有子节点, 加一个大写 R 可以查看递归子节点列表
ls /
创建临时节点
create -e /ephemeral data
create 后跟一个 -e 创建临时节点 , 临时节点不能创建子节点
创建序号节点,加参数 -s
create /seq-parent data // 创建父目录,单纯为了分类,非必须 create -s /seq-parent/ data // 创建顺序节点。顺序节点将再seq-parent 目录下面,顺序递增
为了容纳子节点,先创建个父目录 /seq-parent
也可以再序号节点前面带一个前缀
创建临时顺序节点,其它增删查改和其他节点无异,不再贴图
create -s -e /ephemeral-node/前缀-
创建容器节点
create -c /container
容器节点主要用来容纳字节点,如果没有给其创建子节点,容器节点表现和持久化节点一样,如果给容器节点创建了子节点,后续又把子节点清空,容器节点也会被zookeeper删除。
2. 事件监听机制:
针对节点的监听:一定事件触发,对应的注册立刻被移除,所以事件监听是一次性的
get -w /path // 注册监听的同时获取数据
stat -w /path // 对节点进行监听,且获取元数据信息
针对目录的监听,如下图,目录的变化,会触发事件,且一旦触发,对应的监听也会被移除,后续对节点的创建没有触发监听事件
ls -w /path
针对递归子目录的监听
ls -R -w /path : -R 区分大小写,一定用大写
如下对/test 节点进行递归监听,但是每个目录下的目录监听也是一次性的,如第一次在/test 目录下创建节点时,触发监听事件,第二次则没有,同样,因为时递归的目录监听,所以在/test/sub0下进行节点创建时,触发事件,但是再次创建/test/sub0/subsub1节点时,没有触发事件。
Zookeeper事件类型一览:
None: 连接建立事件
NodeCreated: 节点创建
NodeDeleted: 节点删除
NodeDataChanged:节点数据变化
NodeChildrenChanged:子节点列表变化
DataWatchRemoved:节点监听被移除
ChildWatchRemoved:子节点监听被移除
4, Zookeeper 客户端使用
1). 原生客户端
由于zookeeper 客户端和服务端源码是绑定在一起的,强烈建议使用和服务端代码相同版本的 客户端
引入 maven
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.8</version>
</dependency>
核心代码:
private static final int SESSION_TIMEOUT = 5000;
private static ZooKeeper zooKeeper;
private static final String ZK_NODE="/zk-node";
private static final String ZK_ADDRESS="192.168.1.100:2181";
public void init() throws IOException, InterruptedException {
final CountDownLatch countDownLatch=new CountDownLatch(1);
zooKeeper=new ZooKeeper(ZK_ADDRESS, SESSION_TIMEOUT, event -> {
if (event.getState()== Watcher.Event.KeeperState.SyncConnected &&
event.getType()== Watcher.Event.EventType.None){
countDownLatch.countDown();
log.info("连接成功!");
}
});
log.info("连接中....");
countDownLatch.await();
}
init 方法被执行后,就可以用zookeeper 实例进行操作
完整代码已提交到代码库,需要找班主任开启权限
2). curator
官网 http://curator.apache.org/
引入curator
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.0.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.8</version>
</dependency>
初始化CuratorFramework , 并且调用 start 方法后, 就可以进行 对Zookeeper服务端的操作了。
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3)
CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConnectionString, retryPolicy);
client.start();
完整代码已提交到代码库,需要找班主任开启权限
5, 经典应用场景分析
配置中心
注册中心
分布锁-非公平锁,公平锁,共享锁
1,非公平锁
2,公平锁
请求进来,直接在/lock 节点下创建一个临时顺序节点
判断自己是不是lock节点下,最小的节点
a. 是最小的,获得锁
b. 不是。对前面的节点进行监听( watch)
获得锁的请求,处理完释放锁,即 delete 节点,然后后继第一个节点将收到通知,
重复第2 步判断
3,共享锁
1. read 请求,如果前面的节点都是读锁,直接获取锁,如果read请求前面有写请求,
则该读请求不能获得锁,即需要对前面的写节点进行监听,如果是多个写请求,则
对最后的写请求进行监听
2. write 请求,只需要对前面的节点进行监听和互斥锁处理机制一样
6.精彩录播视频
Redis核心源码分析
Redis架构及集群分片原理
网络底层原理
Zookeeper分布式锁
Mysql性能优化
Zookeeper注册中心与配置中心
喜欢的话可以给小编一个三连,点击下面链接可以领取Java学习资料哦