Zookeeper学习
基本概念
大数据生态系统里很多组件的命名都是某种动物,例如Hadoop是🐘,hive是🐝,zookeeper就是动物园管理者,是管理大数据生态系统各组件的管理员
Zookeeper是经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能,高可用,且具有严格顺序访问控制能力的分布式协调存储服务
应用场景
-
维护配置信息
Java编程经常会遇到配置项,例如数据库的user、password等,通常配置信息会放在配置文件中,再把配置文件放在服务器上。当需要修改配置信息时,要去服务器上修改对应的配置文件,但在分布式系统中很多服务器都需要使用该配置文件,因此必须保证该配置服务的高可用性和各台服务器上配置的一致性。通常会将配置文件部署在一个集群上,但一个集群涉及的服务器数量是很庞大的,如果一台台服务器逐个修改配置文件是效率很低且危险的,因此需要一种服务可以高效快速且可靠地完成配置项的更改工作。Zookeeper就可以提供这种服务,使用Zab一致性协议保证一致性。在开源消息队列Kafka中,也使用zookeeper来维护broker的信息。在dubbo中也广泛使用Zookeeper管理一些配置来实现服务治理 -
分布式锁服务
一个集群是一个分布式系统,由多台服务器组成。为了提高并发度和可靠性,在多台服务器运行着同一种服务。当多个服务在运行时就需要协调各服务的进度,有时候需要保证当某个服务在进行某个操作时,其他的服务都不能进行该操作,即对该操作进行加锁,如果当前机器故障,释放锁并fail over到其他机器继续执行 -
集群管理
Zookeeper会将服务器加入/移除的情况通知给集群中其他正常工作的服务器,以及即使调整存储和计算等任务的分配和执行等,此外Zookeeper还会对故障的服务器做出诊断并尝试修复 -
生成分布式唯一ID
在过去的单库单表系统中,通常使用数据库字段自带的auto_increment熟悉自动为每条记录生成一个唯一的id。但分库分表后就无法依靠该属性来标识一个唯一的记录。此时可以使用Zookeeper在分布式环境下生成全局唯一性id。每次要生成一个新id时,创建一个持久顺序结点,创建操作返回的结点序号,即为新id,然后把比自己结点小的删除
设计目标
-
高性能
将数据存储在内存中,直接服务于客户端的所有非事务请求,尤其适合读为主的应用场景 -
高可用
一般以集群方式对外提供服务,每台机器都会在内存中维护当前的服务状态,每台机器之间都保持通信。只要集群中超过一般机器都能正常工作,那么整个集群就能够正常对外服务 -
严格顺序访问
对于客户端的每个更新请求,zookeeper都会生成全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序
数据结构
Zookeeper的数据结点可以视为树状结构(或者目录),树中各节点成为znode,一个znode可以有多个子结点。Zookeeper结点在结构上表现为树状,使用路径来定位某个znode
znode兼具文件和目录两种特点,既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分
znode结构
- 结点的数据
- 结点的子结点
- 结点的状态
结点类型(在创建时被确定且不能更改)
- 临时结点:生命周期依赖于创建它的会话,会话结束结点将被自动删除。临时结点不允许拥有子结点
- 持久化结点:生命周期不依赖于会话,只有在客户端显式执行删除操作时才被删除
安装启动
安装
下载然后tar解压
去到conf目录下,复制一份zoo_sample.cfg 命名为zoo.cfg
修改dataDir为自己的目录,其他配置可以默认

启动
来到bin目录下
直接 sh zkServer.sh 不可以,会提示你怎么使用

我们要启动的话就是
sh zkServer.sh start 就可以了

sh zkServer.sh start-foreground是前台启动,可以看到一些日志信息

我们在用sh zkServer.sh status查看Zookeeper启动状态

关闭就很简单了sh zkServer.sh stop

命令行操作
查看版本
echo stat|nc localhost 2181 查看Zookeeper版本
本博客是基于Zookeeper 3.7.0的

create
ZooKeeper不支持创建多级,必须要有父级,才能继续创建
首先创建一级节点 zk,数据为parent
create /zk parent

create 命令用法
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
create 默认创建的是持久化节点
-s
-s 用于指定创建顺序节点,单独使用代表创建持久化顺序节点

-c
-c 用于创建container节点,当container节点的最后一个子节点被删除,这个container节点也会被删除

-e
-e 用于创建临时节点,临时结点在会话结束后会被删除
-t
首先要配置,可以看我这一篇博客
create -t 10000 /zk/ttlnode ttl单位为毫秒,所以上述命令创建一个过期时间为10秒的node

十秒后,可以看到节点消失(过期)了

get
先创建一个持久化节点

直接get /zk/testnode可以获得这个节点的数据

-s
-s 可以获取更详细的信息
- cZxid 数据结点创建时的事务id
- ctime 数据结点创建时间
- mZxid 数据结点最后一次更新时的事务id
- mtime 数据结点最后一次更新的时间
- pZxid 子结点最后一次修改的事务id
- cversion 子结点的更改次数
- dataVersion 结点数据更改次数
- aclVersion 结点ACL的更改次数
- ephemeralOwner 如果是临时结点,表示会话的sessionID;如果是持久结点值为0
- dataLength 数据内容长度
- numChildren 子结点数

-w
-w设置一个监听器,当节点的数据被修改时会收到提示
get -w /zk/testnode

getAllChildrenNumber
得到节点所有的子节点个数(不仅仅是一级的子节点)

getEphemerals
得到当前session下所有的临时节点

set
更新数据

-s
更新并得到节点的具体信息

-v
通过CAS来更新数据,CAS的概念大家都很熟悉了,这里如果版本不对,无法更新成功
当前版本为3,而想修改的版本为2,所以不对


delete
删除某个节点

deleteall
删除某个路径下的全部节点以及它本身

ls
列出某个节点的全部子节点

-s
-s 表示除了列出子节点还列出节点的详细信息

-R
递归地展示子节点

-w
设置监听器,当节点的子节点发生变化时有提示

伪集群模式搭建
复制三份配置文件zoo1.cfg、zoo2.cfg、zoo3.cfg


修改三个位置
- dataDir:修改每个节点的存储数据目录位置
- clientPort:1号节点2181,2号节点2182,3号节点2183
- 集群配置:
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
三份文件都修改成功后
还需要在data目录中配置myid文件,myid文件中存放对应节点的序号
echo '1' > /home/program/zookeeper/node1data/myid
echo '2' > /home/program/zookeeper/node2data/myid
echo '3' > /home/program/zookeeper/node3data/myid
启动
sh ./bin/zkServer.sh start ./conf/zoo1.cfg
sh ./bin/zkServer.sh start ./conf/zoo2.cfg
sh ./bin/zkServer.sh start ./conf/zoo2.cfg
查看状态



Java API 操作
首先引入Maven依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.31</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.31</version>
</dependency>
然后创建CuratorFramework
public static CuratorFramework getCurator(int sessionTimeoutMs, int connectionTimeoutMs) {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
// return CuratorFrameworkFactory.builder()
// .connectString("1.2.3.4:2181")
// .sessionTimeoutMs(sessionTimeoutMs)
// .connectionTimeoutMs(connectionTimeoutMs)
// .retryPolicy(retryPolicy)
// .build();
return CuratorFrameworkFactory.newClient("1.2.3.4:2181", sessionTimeoutMs,connectionTimeoutMs,retryPolicy);
}
public static CuratorFramework getCurator() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
return CuratorFrameworkFactory.newClient("1.2.3.4:2181", retryPolicy);
}
最简单的构造方法只要指定重试策略和Zookeeper的地址和端口就可以
有7中重试策略

创建节点
String path = client.create().forPath("/zk/curator");
System.out.println(path);
//还可以直接在forPath里添加数据
String path = client.create().forPath(path,data.getBytes());
返回节点路径

默认创建的是持久化节点
创建临时节点,加上WithMode就可以
client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
client.create().withMode(CreateMode.EPHEMERAL).forPath(path,data.getBytes());
CreateMode这个枚举中就有所有的模式

递归创建节点,这个操作在CLI中不行
client.create().creatingParentsIfNeeded().forPath("/curator/test/test/test");

删除节点
删除一个子节点
client.delete().forPath(path);
删除节点并递归删除其子节点
client.delete().deletingChildrenIfNeeded().forPath(path);
指定版本进行删除
client.delete().withVersion(1).forPath(path);
如果此版本已经不存在,则删除异常,异常信息:Exception in thread "main" org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for XXX
强制保证删除一个节点。只要客户端会话有效,那么Curator会在后台持续进行删除操作,直到节点删除成功。比如遇到一些网络异常的情况,此guaranteed的强制删除就会很有效果。
client.delete().guaranteed().forPath(path);
读取数据
System.out.println("普通查询");
byte[] bytes = client.getData().forPath(path);
System.out.println(new String(bytes, StandardCharsets.UTF_8));
System.out.println("带状态的查询");
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath(path);
System.out.println(stat);

更新数据
更新数据,如果未传入version参数,那么更新当前最新版本,如果传入version则更新指定version,如果version已经变更,则抛出异常。
// 普通更新
client.setData().forPath(path,"新内容".getBytes());
// 指定版本更新
client.setData().withVersion(1).forPath(path);
版本不一致,则抛出异常,异常信息:Exception in thread "main" org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for XXX
监听
可以查看这篇博客,写的很详细了
Curator 的事件监听
缺少的内容
ACL
Zookeeper的分布式锁

浙公网安备 33010602011771号