目录
使用场景
解决数据一致性性问题,本质上是一个存储配置文件的数据库
集群规划
ip 主机名 myid的值
192.168.83.180 node01 1
192.168.83.190 node02 2
192.168.83.200 node03 3
myid这个编号,编号数值越大,在选举中他越有可能成为leader
zookeeper安装
1.下载zookeeper安装包
这里问问使用的zookeeper安装包版本是3.4.9
下载地址
2.解压
tar -xvf zookeeper-3.4.9.tar.gz -C ../servers/
3.修改配置文件
第一台机器修改配置文件
cd /export/servers/zookeeper-3.4.9/conf/
cp zook_sample.cfg zoo.cfg
mkdir -p /export/servers/zookeeper-3.4.9/zkdatas
vim zoo.cfg
# 指定数据存储位置
dataDir=/export/servers/zookeeper-3.4.9/zkdatas
# 保留多少个文件数,zookeeper会生成各种日志文件,这里是保留多少个
autopurge.snapRetainCount=3
# 日志多少小时清理一次
autopurge.purgeInterval=1
/* 集群中服务器地址:描述了整个zookeeper集群的配置,server.1是myid是1的服务器叫node01,后面的2888:3888表示该服务器对应得端口
*/
server.1=node01:2888:3888
server.2=node02:2888:3888
server.3=node03:2888:3888
4.添加myid配置
步骤1.
创建zkdatas目录
mkdir /export/servers/zookeeper-3.4.9/zkdatas
步骤2.
zkdatas目录下创建文件myid内部写入1
vim myid
5.安装包分发到其他机器并修改myid的值
第一台机器执行以下两个命令
scp -r /export/servers/zookeeper-3.4.9/ node02:/export/servers/
scp -r /export/servers/zookeeper-3.4.9/ node03:/export/servers/
第二台机器
echo 2 > /export/servers/zookeeper-3.4.9/zkdatas/myid
第三台机器
echo 3 > /export/servers/zookeeper-3.4.9/zkdatas/myid
6.启动zookeeper集群
三台机器依次执行
/export/servers/zookeeper-3.4.9/bin/zkServer.sh start
查看启动状态
jps
如果一旦没有,再次启动,使用jps还是没有启动成功.那么问题肯定在zoo.cfg这个配置文件,
配置的内容有误,需要打开再次确定.
zookeeper的shell客户端操作
1.登录zookeeper客户端
# -server表示我要和那个主机相连qiut
/export/servers/zookeeper-3.4.9/bin/zkCli.sh -server node01:2181
2.zookeeper客户端操作命令
命令 | 说明 |
---|---|
create [-s] [-e] path data acl | 创建Znode -s指定是顺序节点-e指定是临 |
ls path [watch] | 列出Path下所有子Znode |
get path [watch] | 列出Path下所有子Zonde |
ls2 path [watch] | 获取Path对应得Znode得数据和属性 |
set path data [version] | 更新节点 |
delete path | 删除节点,如果要删除的节点有子Znode则无法删除 |
[version] | Znode则无法删除 |
rmr path | 删除节点,如果有子Znode则地柜删除 |
histort | 列出历史记录 |
操作实例
1.列出Ptath下的所有Znode
ls /
2.创建永久节点
# 在根目录下创建hell节点,携带参数world
create /hello world
3.创建临时节点
临时节点不能创建子节点
create -e /abc 123
4.创建永久化节点
create -s /zhangsan boy
5.创建临时系列化节点
create -e -s /lisi boy
6.修改节点数据
set /hello zookeeper
7.删除节点,如果要删除的节点有子Znode则无法删除
delete /hello
8.删除节点,如果有子Znode则递归删除
rmr /abc
9.列出历史操作
history
zookeeper节点属性
每个znode都包含了一系列的属性,通过get命令,可以获得节点的属性
dataVersion:数据版本号,就你每当进行一次set操作,dataVersion的值都会增加1,主要作用是标识更新数据的先后顺序.
cversion:子节点的版本号
aclVersion:ACL的版本号
cZxid:Znode创建的事务id
mZxid:Znode被修改的事物id,即每次对Znode的修改都会更新mZxid,值越大表示数据越新
ctime:创建节点的时间戳
mtime:接到最新一次更新发生时的时间戳
zookeeper的watch机制
watch机制就是给zookeeper的摸一个Znode节点设置监听,当Znode节点发送变化时,会触发watch,通知相应客户端
watch机制只能触发一次,如果想多次触发,需要多次添加
zookeeper的javaAPI操作
这里我们使用的是一套zookeeper的成熟的客户端框架Curator
1.Curator包简介:
- currator-framework:对zookeeper的底层api的一些封装
- curator-recipes:封装了一些高级特性,如:Cache事件监听,选举,分布式锁,分布式计数器等
2.Maven依赖配置:
- 使用curator的版本:2.12.0,对应zookeeper的版本为:3.4.x,如果跨版本会有兼容性的问题,很有可能导致节点操作失败
3.创建java工程,导入jar包
<!-- <repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/clouderarepos/</url>
</repository>
</repositories> -->
<dependencies>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
4.节点操作
(1)创建永久节点
package cn.itcast.zoopeeprt_api;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.Test;
public class ZookeeperAPITest {
@Test
public void creatZonde() throws Exception {
//1.定制一个重试策略
/* param1:重试间隔时间
param2:重试间隔次数
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,1);
//2.获取一个客户端对象
/* param1:服务器连接列表字符串
param2:会话超时
param3:连接超时
param4:重试要使用的策略
*/
String connectionStr = "192.168.83.180:2181,192.168.83.190:2181,192.168.83.2000:2181";
CuratorFramework client = CuratorFrameworkFactory.newClient(connectionStr, 8000, 8000, retryPolicy);
//3.开启客户端
client.start();
//4.创建永久节点节点
client.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/hello2","world".getBytes());
//5.关闭客户端
client.close();
}
}
运行完成后我们用shell命令查看一下是否创建
查看一下ClassMode源码
(2)创建临时节点
临时节点就是在上述代码中做一些调整,就完成了创建临时节点
CreateMode.EPHEMERAL
(3)修改节点数据
package cn.itcast.zoopeeprt_api;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.Test;
public class ZookeeperAPITest {
@Test
public void creatZonde() throws Exception {
//1.定制一个重试策略
/* param1:重试间隔时间
param2:重试间隔次数
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(5000,1);
//2.获取一个客户端对象
/* param1:服务器连接列表字符串
param2:会话超时
param3:连接超时
param4:重试要使用的策略
*/
String connectionStr = "192.168.83.180:2181,192.168.83.190:2181,192.168.83.200:2181";
CuratorFramework client = CuratorFrameworkFactory.newClient(connectionStr, 8000, 8000, retryPolicy);
//3.开启客户端
client.start();
//4.修改节点数据
client.setData().forPath("/hello2","hello2".getBytes());
//5.关闭客户端
client.close();
}
}
(4)查询节点数据
package cn.itcast.zoopeeprt_api;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.Test;
public class ZookeeperAPITest {
@Test
public void creatZonde() throws Exception {
//1.定制一个重试策略
/* param1:重试间隔时间
param2:重试间隔次数
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(5000,1);
//2.获取一个客户端对象
/* param1:服务器连接列表字符串
param2:会话超时
param3:连接超时
param4:重试要使用的策略
*/
String connectionStr = "192.168.83.180:2181,192.168.83.190:2181,192.168.83.200:2181";
CuratorFramework client = CuratorFrameworkFactory.newClient(connectionStr, 8000, 8000, retryPolicy);
//3.开启客户端
client.start();
//4.查询节点数据
byte[] forPath = client.getData().forPath("/hello2");
System.out.println(new String(forPath));
//5.关闭客户端
client.close();
}
}
(5)节点watch机制
package cn.itcast.zoopeeprt_api;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.Test;
public class ZookeeperAPITest {
@Test
public void creatZonde() throws Exception {
//1.定制一个重试策略
/* param1:重试间隔时间
param2:重试间隔次数
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(5000,1);
//2.获取一个客户端对象
/* param1:服务器连接列表字符串
param2:会话超时
param3:连接超时
param4:重试要使用的策略
*/
String connectionStr = "192.168.83.180:2181,192.168.83.190:2181,192.168.83.200:2181";
CuratorFramework client = CuratorFrameworkFactory.newClient(connectionStr, 8000, 8000, retryPolicy);
//3.开启客户端
client.start();
//4.设置节点的cache
TreeCache treeCache = new TreeCache(client, "/hello2"); //监控那个节点
//5.设置监听和处理过程
treeCache.getListenable().addListener(new TreeCacheListener() { //获取监听容器.添加一个自定义监听器
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
ChildData data = treeCacheEvent.getData();
if (data!=null){
switch (treeCacheEvent.getType()){ //获取事件触发的类型
case NODE_ADDED: //新增节点
System.out.println("监控到有新增节点");
break;
case NODE_REMOVED:
System.out.println("监控到有节点被移除");
break;
case NODE_UPDATED:
System.out.println("监控到有节点数据被更改");
break;
}
}
}
});
//6.开始监听
treeCache.start();
//7.程序从上到下运行,直接就结束了,这里我们需要一个延时,把程序挂起
Thread.sleep(100000000);
}
}
zk的选举机制
就是一张桌子上有一个票,让一堆机器,进行抢,谁抢到谁就是master,领导,其他的节点就是工人,他每隔几秒就选举一次,选举前本身就是领导的机器,他有优先权,所以他不挂掉,他会一直站着这个master的位置,其他节点只能当工人,但是一点他挂掉,剩下的机器都是没有优先权的,谁抢到谁,谁就晋升为master.