本篇文章来自黑马程序员ZooKeeper教程
三天学会ZooKeeper第一天(全网最细)
三天学会ZooKeeper第二天(全网最细)
curator简介
curator是Netflix公司开源的一个zookeeper客户端,后捐献给apache, curator框架在zookeeper原生API接口上进行了包装,解决了很多zooKeeper客户端非常底层的细节开发。提供zooKeeper各种应用场景(比如:分布式锁服务、集群领导选举、共享计数器、缓存机制、分布式队列等)的抽象封装,实现了Fluent风格的API接口,是最好用,最流行的zookeeper的客户端。
原生zookeeperAPI的不足:
curator特点:
Curator的组件
Maven依赖
我们在实际的应用时,最常用的是curator-recipes。
连接到ZooKeeper
依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.2.0</version>
</dependency>
public class testConnection {
public static void main(String[] args) {
// session重连策略
/*
3秒后重连一次,只重连1次
RetryPolicy retryPolicy = new RetryOneTime(3000);
*/
/*
每3秒重连一次,重连3次
RetryPolicy retryPolicy = new RetryNTimes(3,3000);
*/
/*
每3秒重连一次,总等待时间超过10秒后停止重连
RetryPolicy retryPolicy=new RetryUntilElapsed(10000,3000);
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory.builder()
// IP地址端口号
.connectString("192.168.1.108")
// 会话超时时间
.sessionTimeoutMs(5000)
// 重连机制
.retryPolicy(retryPolicy)
// 命名空间
.namespace("create")
// 构建连接对象
.build();
client.start();
System.out.println(client.isStarted());
client.close();
}
}
官网的打开连接方式
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3)
CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConnectionString, retryPolicy);
client.start();
新增节点
public class testCreate {
private String ip="192.168.1.108:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("create").build();
client.start();
}
@Test
public void create()throws Exception{
client.create()
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.READ_ACL_UNSAFE)
.forPath("/node","node1".getBytes());
System.out.println("end!!!");
}
@Test
public void create2() throws Exception{
// 自定义权限列表
// 权限列表
List<ACL> list = new ArrayList<ACL>();
// 授权模式和授权对象
Id id = new Id("ip", "192.168.1.102");
list.add(new ACL(ZooDefs.Perms.ALL, id));
client.create().withMode(CreateMode.PERSISTENT).withACL(list).
forPath("/node2", "node2".getBytes());
System.out.println("结束");
}
@Test
public void create3()throws Exception{
// 递归创建节点树
client.create()
// 递归节点的创建
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath("/node3/node31", "node31".getBytes());
System.out.println("结束");
}
@Test
public void create4() throws Exception {
// 异步方式创建节点
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
// 异步回调接口
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework
curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 节点的路径
System.out.println(curatorEvent.getPath());
// 时间类型
System.out.println(curatorEvent.getType());
}
})
.forPath("/node4","node4".getBytes());
Thread.sleep(5000);
System.out.println("结束");
}
@After
public void close(){
client.close();
}
}
更新节点
public class TestSet {
private String ip="192.168.1.102:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("set").build();
client.start();
}
@Test
public void set1() throws Exception {
// 更新节点
client.setData()
// arg1:节点的路径
// arg2:节点的数据
.forPath("/node1", "node11".getBytes());
System.out.println("结束");
}
@Test
public void set2() throws Exception {
client.setData()
// 指定版本号
.withVersion(2)
.forPath("/node1", "node1111".getBytes());
System.out.println("结束");
}
@Test
public void set3() throws Exception {
// 异步方式修改节点数据
client.setData()
.withVersion(-1).inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework,
CuratorEvent curatorEvent) throws Exception {
// 节点的路径
System.out.println(curatorEvent.getPath());
// 事件的类型
System.out.println(curatorEvent.getType());
}
}).forPath("/node1", "node1".getBytes());
Thread.sleep(5000);
System.out.println("结束");
}
@After
public void close(){
client.close();
}
}
删除节点
public class testDelete {
private String ip="192.168.1.102:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("create").build();
client.start();
}
@Test
public void delete1() throws Exception {
// 删除节点
client.delete()
// 节点的路径
.forPath("/node1");
System.out.println("结束");
}
@Test
public void delete2() throws Exception {
client.delete()
// 版本号
.withVersion(0)
.forPath("/node1");
System.out.println("结束");
}
@Test
public void delete3() throws Exception {
//删除包含字节点的节点
client.delete()
.deletingChildrenIfNeeded()
.withVersion(-1)
.forPath("/node1");
System.out.println("结束");
}
@Test
public void delete4() throws Exception {
// 异步方式删除节点
client.delete()
.deletingChildrenIfNeeded()
.withVersion(-1)
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework
curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 节点路径
System.out.println(curatorEvent.getPath());
// 事件类型
System.out.println(curatorEvent.getType());
}
})
.forPath("/node1");
Thread.sleep(5000);
System.out.println("结束");
}
@After
public void close(){
client.close();
}
}
查看节点
public class TestGet {
private String ip="192.168.1.102:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("create").build();
client.start();
}
@Test
public void get1() throws Exception {
// 读取节点数据
byte [] bys=client.getData()
// 节点的路径
.forPath("/node1");
System.out.println(new String(bys));
}
@Test
public void get2() throws Exception {
// 读取数据时读取节点的属性
Stat stat=new Stat();
byte [] bys=client.getData()
// 读取属性
.storingStatIn(stat)
.forPath("/node1");
System.out.println(new String(bys));
System.out.println(stat.getVersion());
}
@Test
public void get3() throws Exception {
// 异步方式读取节点的数据
client.getData()
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework
curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 节点的路径
System.out.println(curatorEvent.getPath());
// 事件类型
System.out.println(curatorEvent.getType());
// 数据
System.out.println(new
String(curatorEvent.getData()));
}
})
.forPath("/node1");
Thread.sleep(5000);
System.out.println("结束");
}
@After
public void close(){
client.close();
}
}
查看子节点
public class TestGetchlden {
private String ip="192.168.1.102:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("get").build();
client.start();
}
@After
public void close(){
client.close();
}
@Test
public void getChild1() throws Exception {
// 读取子节点数据
List<String> list = client.getChildren()
// 节点路径
.forPath("/get");
for (String str : list) {
System.out.println(str);
}
}
@Test
public void getChild2() throws Exception {
// 异步方式读取子节点数据
client.getChildren()
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework
curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 节点路径
System.out.println(curatorEvent.getPath());
// 事件类型
System.out.println(curatorEvent.getType());
// 读取子节点数据
List<String> list=curatorEvent.getChildren();
for (String str : list) {
System.out.println(str);
}
}
})
.forPath("/get");
Thread.sleep(5000);
System.out.println("结束");
}
}
检查子节点是否存在
public class TestExist {
private String ip="192.168.1.102:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("get").build();
client.start();
}
@After
public void close(){
client.close();
}
@Test
public void exists1() throws Exception {
// 判断节点是否存在
Stat stat= client.checkExists()
// 节点路径
.forPath("/node2");
System.out.println(stat.getVersion());
}
@Test
public void exists2() throws Exception {
// 异步方式判断节点是否存在
client.checkExists()
.inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework
curatorFramework, CuratorEvent curatorEvent) throws Exception {
// 节点路径
System.out.println(curatorEvent.getPath());
// 事件类型
System.out.println(curatorEvent.getType());
System.out.println(curatorEvent.getStat().getVersion());
}
})
.forPath("/node2");
Thread.sleep(5000);
System.out.println("结束");
}
}
watcherAPI
Node Cache : 只是监听某一个特定的节点,监听节点的新增和修改
PathChildren Cache : 监控一个ZNode的子节点. 当一个子节点增加, 更新,删除
时, Path Cache会改变它的状态, 会包含最新的子节点, 子节点的数据和状态
public class CuratorWatcher {
private String ip="192.168.1.108:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("create").build();
client.start();
}
@After
public void close(){
client.close();
}
@Test
public void watcher1() throws Exception {
// 监视某个节点的数据变化
// arg1:连接对象
// arg2:监视的节点路径
final NodeCache nodeCache=new NodeCache(client,"/watcher1");
// 启动监视器对象
nodeCache.start();
nodeCache.getListenable().addListener(new NodeCacheListener() {
// 节点变化时回调的方法
public void nodeChanged() throws Exception {
System.out.println(nodeCache.getCurrentData().getPath());
System.out.println(new
String(nodeCache.getCurrentData().getData()));
}
});
Thread.sleep(100000);
System.out.println("结束");
//关闭监视器对象
nodeCache.close();
}
@Test
public void watcher2() throws Exception {
// 监视子节点的变化
// arg1:连接对象
// arg2:监视的节点路径
// arg3:事件中是否可以获取节点的数据
PathChildrenCache pathChildrenCache=new PathChildrenCache(client,"/watcher1",true);
// 启动监听
pathChildrenCache.start();
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
// 当子节点方法变化时回调的方法
public void childEvent(CuratorFramework curatorFramework,
PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
// 节点的事件类型
System.out.println(pathChildrenCacheEvent.getType());
// 节点的路径
System.out.println(pathChildrenCacheEvent.getData().getPath());
// 节点数据
System.out.println(new
String(pathChildrenCacheEvent.getData().getData()));
}
});
Thread.sleep(100000);
System.out.println("结束");
// 关闭监听
pathChildrenCache.close();
}
}
事务
public class TestTranction {
private String ip="192.168.1.102:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("get").build();
client.start();
}
@After
public void close(){
client.close();
}
@Test
public void Watch()throws Exception{
client.inTransaction().
create().forPath("node1", "node1".getBytes()).
and().
create().forPath("node2", "node2".getBytes()).
and().
commit();
}
}
分布式锁
InterProcessMutex:分布式可重入排它锁
InterProcessReadWriteLock:分布式读写锁
public class CuratorLock {
private String ip="192.168.1.102:2181";
CuratorFramework client;
RetryPolicy retryPolicy= new RetryUntilElapsed(2000,3);
@Before
public void conn(){
client= CuratorFrameworkFactory.builder().connectString(ip).
sessionTimeoutMs(5000).
retryPolicy(retryPolicy)
.namespace("get").build();
client.start();
}
@After
public void close(){
client.close();
}
@Test
public void lock1() throws Exception {
// 排他锁
// arg1:连接对象
// arg2:节点路径
InterProcessLock interProcessLock = new InterProcessMutex(client,
"/lock1");
System.out.println("等待获取锁对象!");
// 获取锁
interProcessLock.acquire();
for (int i = 1; i <= 10; i++) {
Thread.sleep(3000);
System.out.println(i);
}
// 释放锁
interProcessLock.release();
System.out.println("等待释放锁!");
}
@Test
public void lock2() throws Exception {
// 读写锁
InterProcessReadWriteLock interProcessReadWriteLock=new
InterProcessReadWriteLock(client, "/lock1");
// 获取读锁对象
InterProcessLock
interProcessLock=interProcessReadWriteLock.readLock();
System.out.println("等待获取锁对象!");
// 获取锁
interProcessLock.acquire();
for (int i = 1; i <= 10; i++) {
Thread.sleep(3000);
System.out.println(i);
}
// 释放锁
interProcessLock.release();
System.out.println("等待释放锁!");
}
@Test
public void lock3() throws Exception {
// 读写锁2.zookeeper
InterProcessReadWriteLock interProcessReadWriteLock=new
InterProcessReadWriteLock(client, "/lock1");
// 获取写锁对象
InterProcessLock
interProcessLock=interProcessReadWriteLock.writeLock();
System.out.println("等待获取锁对象!");
// 获取锁
interProcessLock.acquire();
for (int i = 1; i <= 10; i++) {
Thread.sleep(3000);
System.out.println(i);
}
// 释放锁
interProcessLock.release();
System.out.println("等待释放锁!");
}
}
zooKeeper支持某些特定的四字命令与其的交互。它们大多是查询命令,用来
获取 zooKeeper服务的当前状态及相关信息。用户在客户端可以通过 telnet 或 nc 向zooKeeper提交相应的命令。
四字命令格式:
echo [command] | nc [ip] [port]
nc命令工具安装:
#root用户安装
#下载安装包
wget http://vault.centos.org/6.6/os/x86_64/Packages/nc-1.84-
22.el6.x86_64.rpm
#rpm安装
rpm -iUv nc-1.84-22.el6.x86_64.rpm
echo mntr | nc localhost 2181
conf:输出相关服务配置的详细信息
shell终端输入:echo conf| nc localhost 2181
cons命令
cons:列出所有连接到这台服务器的客户端连接/会话的详细信息
shell终端输入:echo cons| nc localhost 2181
[root@localhost bin]# echo cons |nc localhost 2181
/0:0:0:0:0:0:0:1:35706[0](queued=0,recved=1,sent=0)
/127.0.0.1:48042[1](queued=0,recved=2,sent=2,sid=0x179cb9a49b80000,lop=PING,est=1622619217920,
to=30000,lcxid=0x0,lzxid=0xd,lresp=1622619227956,llat=0,minlat=0,avglat=1,maxlat=3)
crst:重置当前这台服务器所有连接/会话的统计信息
shell终端输入:echo crst| nc localhost 2181
dump命令
dump:列出未经处理的会话和临时节点
shell终端输入:echo dump| nc localhost 2181
envi命令
envi:输出关于服务器的环境配置信息
shell终端输入:echo envi| nc localhost 2181
ruok命令
ruok:测试服务是否处于正确运行状态
shell终端输入:echo ruok| nc localhost 2181
stat命令
stat:输出服务器的详细信息与srvr相似,但是多了每个连接的会话信息
shell终端输入:
echo stat| nc localhost 2181
srst:重置server状态
shell终端输入:echo srst| nc localhost 2181
wchs命令
wchs:列出服务器watches的简洁信息
shell终端输入:echo wchs| nc localhost 2181
wchc命令
wchc:通过session分组,列出watch的所有节点,它的输出的是一个与 watch 相关的会话的节点列表
shell终端输入:echo wchc| nc localhost 2181
问题
解决方法:
# 修改启动指令 zkServer.sh
# 注意找到这个信息
else
echo "JMX disabled by user request" >&2
ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
fi
# 下面添加如下信息
ZOOMAIN="-Dzookeeper.4lw.commands.whitelist=* ${ZOOMAIN}"
wchp命令
wchp:通过路径分组,列出所有的 watch 的session id信息
shell终端输入:echo wchc| nc localhost 2181
问题
wchp is not executed because it is not in the whitelist.
解决方法:
# 修改启动指令 zkServer.sh
# 注意找到这个信息
else
echo "JMX disabled by user request" >&2
ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
fi
# 下面添加如下信息
ZOOMAIN="-Dzookeeper.4lw.commands.whitelist=* ${ZOOMAIN}"
mntr命令
mntr:列出服务器的健康状态
shell终端输入:echo mntr| nc localhost 2181
ZooInspector下载地址:
https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip
解压后进入目录ZooInspector\build,运行zookeeper-dev-ZooInspector.jar
#执行命令如下
java -jar zookeeper-dev-ZooInspector.jar
基于zookeeper的监控管理工具taokeeper,由淘宝团队开源的zk管理中间件,安装前要求服务前先配置nc 和 sshd
1.下载数据库脚本
wget https://github.com/downloads/alibaba/taokeeper/taokeeper.sql
2.下载主程序
wget wget https://github.com/downloads/alibaba/taokeeper/taokeeper-monitor.tar.gz
3.下载配置文件
wget https://github.com/downloads/alibaba/taokeeper/taokeeper-monitor-config.properties
4.配置 taokeeper-monitor-config.properties
wget https://github.com/downloads/alibaba/taokeeper/taokeeper-monitorconfig.properties5.安装配置 tomcat,修改catalina.sh
6.部署工程启动
#Daily
systemInfo.envName=DAILY
#DBCP
dbcp.driverClassName=com.mysql.jdbc.Driver
#mysql连接的ip地址端口号
dbcp.dbJDBCUrl=jdbc:mysql://192.168.60.130:3306/taokeeper
dbcp.characterEncoding=GBK
#用户名
dbcp.username=root
#密码
dbcp.password=root
dbcp.maxActive=30
dbcp.maxIdle=10
dbcp.maxWait=10000
#SystemConstant
#用户存储内部数据的文件夹
#创建/home/zookeeper/taokeeperdata/ZooKeeperClientThroughputStat
SystemConstent.dataStoreBasePath=/home/zookeeper/taokeeperdata
#ssh用户
SystemConstant.userNameOfSSH=zookeeper
#ssh密码
SystemConstant.passwordOfSSH=zookeeper
#Optional
SystemConstant.portOfSSH=22
#指向配置文件所在的位置
JAVA_OPTS=-DconfigFilePath="/home/zookeeper/taokeeper-monitortomcat/webapps/ROOT/conf/taokeeper-monitor-config.properties
5.安装配置 tomcat,修改catalina.sh
#指向配置文件所在的位置
JAVA_OPTS=-DconfigFilePath="/home/zookeeper/taokeeper-monitortomcat/webapps/ROOT/conf/taokeeper-monitor-config.propert
6.部署工程启动