一、zookeeper简介说明
重启zookeeper时需要关闭防火墙????
与eclipse集成的管理zookeeper的工具:
在eclipse点击help,然后点击install new software,点击add,输入名称和网址,网址是:
http://www.massedynamic.org/eclipse/updates/
1、什么是zookeeper
2、zookeeper的结构
zookeeper会维护一个具有层次关系的数据结构,它非常类似于一个标准的文件系统(树状结构)
3、zookeeper组成
zk server根据其身份特性分为三种:leader,Follower,Observer,其中Follower和Observer又统称为Learner(学习者)
Leader:负责客户端的writer类型请求
Follower:负责客户端的reader类型请求,参与leader选举等
Observer:特殊的“Follower”,其可以接受客户端reader请求,但不参与选举。(监控者)
4、zookeeper的应用场景
配置管理
集群管理
发布与订阅
数据库切换
分布式日志的收集
分布式锁、队列管理等等
二、搭建zookeeper与配置文件说明
1、步骤
①、将zookeeper-3.4.5.tar.gz上传到linux的devsoft目录下
②、解压到/usr/local下
命令:tar -zxvf zookeeper-3.4.5.tar.gz -C /usr/local/
③、重命名,在 /usr/local/目录下操作
mv zookeeper-3.4.5 zookeeper
④、修改环境变量:vi /etc/profile
export ZOOKEEPER_HOME=/usr/local/zookeeper
export PATH=.:$ZOOKEEPER_HOME/bin:$JAVA_HOME/...
⑤、刷新
source /etc/profile
⑥、到zookeeper下修改配置文件
cd /usr/local/zookeeper/conf
mv zoo_sample.cfg zoo.cfg
⑦、修改conf: vi zoo.cfg 修改两处
(1)dataDir=/usr/local/zookeeper/data
(2)最后面添加
server.0=192.168.1.103:2888:3888
server.1=192.168.1.104:2888:3888
server.2=192.168.1.105:2888:3888
⑧、服务器标识配置:
创建文件夹:mkdir data
创建文件myid并填写内容为0,1,2:对应上一步的0,1,2(vi myid)
⑨、启动zookeeper:
路径:/usr/local/zookeeper/bin
执行:zkServer.sh start(注意:这三台机器都要进行启动)
状态:zkServer.sh status(在三个节点上检查zk的mode,一个leader和两个follower)
2、zookeeper客户端操作命令
zkCli.sh 进入zookeeper客户端
各级提示命令进行操作
查找:ls / ls /zookeeper
创建并赋值:create /lptxyl zkp
获取:get /lptxyl
设置:set /lptxyl lipeng
可以看到zookeeper集群的数据一致性
递归删除节点:rmr /path
删除指定某个节点:delete /path/child
创建节点有两种类型:短暂(ephemeral)持久(persistent)
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
三、java操作zookeeper
1、原生API
package com.lptxyl.zookeeper.base;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
public class ZookeeperBase {
//zookeeper的地址
static final String CONNECT_ADDR = "192.168.1.103:2181,192.168.1.104:2181,192.168.1.105:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000; //ms
//阻塞程序执行,用于等待zookeeper连接成功,发送成功信号
static final CountDownLatch connectedSemaphore = new CountDownLatch(1);
static final CountDownLatch connectedSemaphore2 = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
ZooKeeper zk = new ZooKeeper(CONNECT_ADDR, SESSION_OUTTIME, new Watcher() {
@Override
public void process(WatchedEvent event) {
//获取事件的状态
KeeperState keeperState = event.getState();
EventType eventType = event.getType();
//如果是建立连接
if(KeeperState.SyncConnected == keeperState){
if(EventType.None == eventType){
//如果建立连接成功,则发送信号量,让后续阻塞程序向下执行
connectedSemaphore.countDown();
System.out.println("zk 建立连接");
}
}
}
});
//进行阻塞
connectedSemaphore.await();
System.out.println("..");
//同步创建父节点,此外还有异步的一些方法
/**
参数一:节点路径,不允许递归创建节点,也就是没有父节点不能创建子节点
参数二:节点内容,不支持序列化
参数三:节点权限,用Ids.OPEN_ACL_UNSAFE就行
参数四:节点类型
CreateMode.PERSISTENT表示创建的节点是持久化的
CreateMode.PERSISTENT_SEQUENTIAL表示持久顺序节点,有顺序的
CreateMode.EPHEMERAL表示创建的节点是临时的,本次会话有效
CreateMode.EPHEMERAL_SEQUENTIAL表示临时顺序节点
*/
zk.create("/testRoot", "testRoot".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//创建子节点
// zk.create("/testRoot/children", "children data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//获取节点洗信息
// byte[] data = zk.getData("/testRoot", false, null);
// System.out.println(new String(data));
// System.out.println(zk.getChildren("/testRoot", false));
//修改节点的值
// zk.setData("/testRoot", "modify data root".getBytes(), -1);
// byte[] data = zk.getData("/testRoot", false, null);
// System.out.println(new String(data));
//判断节点是否存在
// System.out.println(zk.exists("/testRoot/children", false));
//删除节点,-1这个参数表示版本号,如果是-1,则表示全部删除,不管哪个版本
// zk.delete("/testRoot/children", -1);
// System.out.println(zk.exists("/testRoot/children", false));
zk.close();
}
}
创建临时节点可以实现分布式锁,因为如果两个客户端同时访问zookeeper的同一个节点,那么他们的顺序是
先创建一个临时节点,然后操作,再关闭本次会话。而临时节点如果一旦创建了,就不能创建名字相同的节点
,所以其他客户端不能操作本节点,而临时节点在会话关闭后会自动消失,此时另一个客户端就可以操作这个
节点了
2、watch机制核心讲解
zookeeper有watch事件,是一次性触发的,当watch监视的数据发生变化时,通知设置了该watch的
client,即watcher
同样,其watcher是监听数据发生了某些变化,那就一定会有对应的事件类型和状态类型
事件类型:(znode节点相关的)
EventType.NodeCreated
EventType.NodeDataChanged
EventType.NodeChildrenChanged
EventType.NodeDeleted
状态类型:(是跟客户端实例相关的)
KeeperState.Disconnected
KeeperState.SyncConnected
KeeperState.AuthFailed
KeeperState.Expired
代码在zookeeper项目里面
package com.lptxyl.zookeeper.watch;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
/**
* Zookeeper Wathcher
* 本类就是一个Watcher类(实现了org.apache.zookeeper.Watcher类)
* @author(alienware)
* @since 2015-6-14
*/
public class ZookeeperWatch implements Watcher {
/** 定义原子变量 */
AtomicInteger seq = new AtomicInteger();
/** 定义session失效时间 */
private static final int SESSION_TIMEOUT = 10000;
/** zookeeper服务器地址 */
private static final String CONNECTION_ADDR = "192.168.1.103:2181,192.168.1.104:2181,192.168.1.105:2181";
/** zk父路径设置 */
private static final String PARENT_PATH = "/p";
/** zk子路径设置 */
private static final String CHILDREN_PATH = "/p/c";
/** 进入标识 */
private static final String LOG_PREFIX_OF_MAIN = "【Main】";
/** zk变量 */
private ZooKeeper zk = null;
/**用于等待zookeeper连接建立之后 通知阻塞程序继续向下执行 */
private CountDownLatch connectedSemaphore = new CountDownLatch(1);
/**
* 创建ZK连接
* @param connectAddr ZK服务器地址列表
* @param sessionTimeout Session超时时间
*/
public void createConnection(String connectAddr, int sessionTimeout) {
this.releaseConnection();
try {
//this表示把当前对象进行传递到其中去(也就是在主函数里实例化的new ZooKeeperWatcher()实例对象)
zk = new ZooKeeper(connectAddr, sessionTimeout, this);
System.out.println(LOG_PREFIX_OF_MAIN + "开始连接ZK服务器");
connectedSemaphore.await();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 关闭ZK连接
*/
public void releaseConnection() {
if (this.zk != null) {
try {
this.zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 创建节点
* @param path 节点路径
* @param data 数据内容
* @return
*/
public boolean createPath(String path, String data, boolean needWatch) {
try {
//设置监控(由于zookeeper的监控都是一次性的所以 每次必须设置监控)
this.zk.exists(path, needWatch);
System.out.println(LOG_PREFIX_OF_MAIN + "节点创建成功, Path: " +
this.zk.create( /**路径*/
path,
/**数据*/
data.getBytes(),
/**所有可见*/
Ids.OPEN_ACL_UNSAFE,
/**永久存储*/
CreateMode.PERSISTENT ) +
", content: " + data);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 读取指定节点数据内容
* @param path 节点路径
* @return
*/
public String readData(String path, boolean needWatch) {
try {
System.out.println("读取数据操作...");
return new String(this.zk.getData(path, needWatch, null));
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* 更新指定节点数据内容
* @param path 节点路径
* @param data 数据内容
* @return
*/
public boolean writeData(String path, String data) {
try {
System.out.println(LOG_PREFIX_OF_MAIN + "更新数据成功,path:" + path + ", stat: " +
this.zk.setData(path, data.getBytes(), -1));
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 删除指定节点
*
* @param path
* 节点path
*/
public void deleteNode(String path) {
try {
this.zk.delete(path, -1);
System.out.println(LOG_PREFIX_OF_MAIN + "删除节点成功,path:" + path);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 判断指定节点是否存在
* @param path 节点路径
*/
public Stat exists(String path, boolean needWatch) {
try {
return this.zk.exists(path, needWatch);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取子节点
* @param path 节点路径
*/
private List<String> getChildren(String path, boolean needWatch) {
try {
System.out.println("读取子节点操作...");
return this.zk.getChildren(path, needWatch);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 删除所有节点
*/
public void deleteAllTestPath(boolean needWatch) {
if(this.exists(CHILDREN_PATH, needWatch) != null){
this.deleteNode(CHILDREN_PATH);
}
if(this.exists(PARENT_PATH, needWatch) != null){
this.deleteNode(PARENT_PATH);
}
}
/**
* 收到来自Server的Watcher通知后的处理。
*/
@Override
public void process(WatchedEvent event) {
System.out.println("进入 process 。。。。。event = " + event);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (event == null) {
return;
}
// 连接状态
KeeperState keeperState = event.getState();
// 事件类型
EventType eventType = event.getType();
// 受影响的path
String path = event.getPath();
//原子对象seq 记录进入process的次数
String logPrefix = "【Watcher-" + this.seq.incrementAndGet() + "】";
System.out.println(logPrefix + "收到Watcher通知");
System.out.println(logPrefix + "连接状态:\t" + keeperState.toString());
System.out.println(logPrefix + "事件类型:\t" + eventType.toString());
if (KeeperState.SyncConnected == keeperState) {
// 成功连接上ZK服务器
if (EventType.None == eventType) {
System.out.println(logPrefix + "成功连接上ZK服务器");
connectedSemaphore.countDown();
}
//创建节点
else if (EventType.NodeCreated == eventType) {
System.out.println(logPrefix + "节点创建");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//更新节点
else if (EventType.NodeDataChanged == eventType) {
System.out.println(logPrefix + "节点数据更新");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//更新子节点
else if (EventType.NodeChildrenChanged == eventType) {
System.out.println(logPrefix + "子节点变更");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//删除节点
else if (EventType.NodeDeleted == eventType) {
System.out.println(logPrefix + "节点 " + path + " 被删除");
}
else ;
}
else if (KeeperState.Disconnected == keeperState) {
System.out.println(logPrefix + "与ZK服务器断开连接");
}
else if (KeeperState.AuthFailed == keeperState) {
System.out.println(logPrefix + "权限检查失败");
}
else if (KeeperState.Expired == keeperState) {
System.out.println(logPrefix + "会话失效");
}
else ;
System.out.println("--------------------------------------------");
}
/**
* <B>方法名称:</B>测试zookeeper监控<BR>
* <B>概要说明:</B>主要测试watch功能<BR>
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//建立watcher //当前客户端可以称为一个watcher 观察者角色
ZookeeperWatch zkWatch = new ZookeeperWatch();
//创建连接
zkWatch.createConnection(CONNECTION_ADDR, SESSION_TIMEOUT);
//System.out.println(zkWatch.zk.toString());
Thread.sleep(1000);
// 清理节点
zkWatch.deleteAllTestPath(false);
//-----------------第一步: 创建父节点 /p ------------------------//
if (zkWatch.createPath(PARENT_PATH, System.currentTimeMillis() + "", true)) {
Thread.sleep(1000);
//-----------------第二步: 读取节点 /p 和 读取/p节点下的子节点(getChildren)的区别 --------------//
// 读取数据
// zkWatch.readData(PARENT_PATH, true);
//
// // 读取子节点(监控childNodeChange事件)
zkWatch.getChildren(PARENT_PATH, true);
//
// // 更新数据
// zkWatch.writeData(PARENT_PATH, System.currentTimeMillis() + "");
//
Thread.sleep(1000);
// // 创建子节点
// zkWatch.createPath(CHILDREN_PATH, System.currentTimeMillis() + "", true);
//-----------------第三步: 建立子节点的触发 --------------//
// zkWatch.createPath(CHILDREN_PATH + "/c1", System.currentTimeMillis() + "", true);
// zkWatch.createPath(CHILDREN_PATH + "/c1/c2", System.currentTimeMillis() + "", true);
//-----------------第四步: 更新子节点数据的触发 --------------//
//在进行修改之前,我们需要watch一下这个节点:
// Thread.sleep(1000);
// zkWatch.readData(CHILDREN_PATH, true);
// zkWatch.writeData(CHILDREN_PATH, System.currentTimeMillis() + "");
}
// Thread.sleep(10000);
// 清理节点
// zkWatch.deleteAllTestPath(false);
// Thread.sleep(10000);
zkWatch.releaseConnection();
}
}
3、安全认证
当一个客户端连接zookeeper的某个节点时,如果指定了一个权限认证(相当于密码)
(zk.addAuthInfo(authentication_type,correctAuthentication.getBytes());),那么另外一个客户端连
接此节点操作数据时,也需要同样的指定这个认证的权限(相当于密码)
ZK提供了三种模式:权限模式,授权对象,权限
代码如下:
package com.lptxyl.zookeeper.auth;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
/**
* Zookeeper 节点授权
* @author(alienware)
* @since 2015-6-14
*/
public class ZookeeperAuth implements Watcher {
/** 连接地址 */
final static String CONNECT_ADDR = "192.168.1.103:2181";
/** 测试路径 */
final static String PATH = "/testAuth";
final static String PATH_DEL = "/testAuth/delNode";
/** 认证类型 */
final static String authentication_type = "digest";
/** 认证正确方法 */
final static String correctAuthentication = "123456";
/** 认证错误方法 */
final static String badAuthentication = "654321";
static ZooKeeper zk = null;
/** 计时器 */
AtomicInteger seq = new AtomicInteger();
/** 标识 */
private static final String LOG_PREFIX_OF_MAIN = "【Main】";
private CountDownLatch connectedSemaphore = new CountDownLatch(1);
@Override
public void process(WatchedEvent event) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (event==null) {
return;
}
// 连接状态
KeeperState keeperState = event.getState();
// 事件类型
EventType eventType = event.getType();
// 受影响的path
String path = event.getPath();
String logPrefix = "【Watcher-" + this.seq.incrementAndGet() + "】";
System.out.println(logPrefix + "收到Watcher通知");
System.out.println(logPrefix + "连接状态:\t" + keeperState.toString());
System.out.println(logPrefix + "事件类型:\t" + eventType.toString());
if (KeeperState.SyncConnected == keeperState) {
// 成功连接上ZK服务器
if (EventType.None == eventType) {
System.out.println(logPrefix + "成功连接上ZK服务器");
connectedSemaphore.countDown();
}
} else if (KeeperState.Disconnected == keeperState) {
System.out.println(logPrefix + "与ZK服务器断开连接");
} else if (KeeperState.AuthFailed == keeperState) {
System.out.println(logPrefix + "权限检查失败");
} else if (KeeperState.Expired == keeperState) {
System.out.println(logPrefix + "会话失效");
}
System.out.println("--------------------------------------------");
}
/**
* 创建ZK连接
*
* @param connectString
* ZK服务器地址列表
* @param sessionTimeout
* Session超时时间
*/
public void createConnection(String connectString, int sessionTimeout) {
this.releaseConnection();
try {
zk = new ZooKeeper(connectString, sessionTimeout, this);
//添加节点授权
zk.addAuthInfo(authentication_type,correctAuthentication.getBytes());
System.out.println(LOG_PREFIX_OF_MAIN + "开始连接ZK服务器");
//倒数等待
connectedSemaphore.await();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 关闭ZK连接
*/
public void releaseConnection() {
if (this.zk!=null) {
try {
this.zk.close();
} catch (InterruptedException e) {
}
}
}
/**
*
* <B>方法名称:</B>测试函数<BR>
* <B>概要说明:</B>测试认证<BR>
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ZookeeperAuth testAuth = new ZookeeperAuth();
testAuth.createConnection(CONNECT_ADDR,2000);
List<ACL> acls = new ArrayList<ACL>(1);
for (ACL ids_acl : Ids.CREATOR_ALL_ACL) {
acls.add(ids_acl);
}
try {
zk.create(PATH, "init content".getBytes(), acls, CreateMode.PERSISTENT);
System.out.println("使用授权key:" + correctAuthentication + "创建节点:"+ PATH + ", 初始内容是: init content");
} catch (Exception e) {
e.printStackTrace();
}
try {
zk.create(PATH_DEL, "will be deleted! ".getBytes(), acls, CreateMode.PERSISTENT);
System.out.println("使用授权key:" + correctAuthentication + "创建节点:"+ PATH_DEL + ", 初始内容是: init content");
} catch (Exception e) {
e.printStackTrace();
}
// 获取数据
getDataByNoAuthentication();
getDataByBadAuthentication();
getDataByCorrectAuthentication();
// 更新数据
updateDataByNoAuthentication();
updateDataByBadAuthentication();
updateDataByCorrectAuthentication();
// 删除数据
deleteNodeByBadAuthentication();
deleteNodeByNoAuthentication();
deleteNodeByCorrectAuthentication();
//
Thread.sleep(1000);
deleteParent();
//释放连接
testAuth.releaseConnection();
}
/** 获取数据:采用错误的密码 */
static void getDataByBadAuthentication() {
String prefix = "[使用错误的授权信息]";
try {
ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
//授权
badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
Thread.sleep(2000);
System.out.println(prefix + "获取数据:" + PATH);
System.out.println(prefix + "成功获取数据:" + badzk.getData(PATH, false, null));
} catch (Exception e) {
System.err.println(prefix + "获取数据失败,原因:" + e.getMessage());
}
}
/** 获取数据:不采用密码 */
static void getDataByNoAuthentication() {
String prefix = "[不使用任何授权信息]";
try {
System.out.println(prefix + "获取数据:" + PATH);
ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
Thread.sleep(2000);
System.out.println(prefix + "成功获取数据:" + nozk.getData(PATH, false, null));
} catch (Exception e) {
System.err.println(prefix + "获取数据失败,原因:" + e.getMessage());
}
}
/** 采用正确的密码 */
static void getDataByCorrectAuthentication() {
String prefix = "[使用正确的授权信息]";
try {
System.out.println(prefix + "获取数据:" + PATH);
System.out.println(prefix + "成功获取数据:" + zk.getData(PATH, false, null));
} catch (Exception e) {
System.out.println(prefix + "获取数据失败,原因:" + e.getMessage());
}
}
/**
* 更新数据:不采用密码
*/
static void updateDataByNoAuthentication() {
String prefix = "[不使用任何授权信息]";
System.out.println(prefix + "更新数据: " + PATH);
try {
ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
Thread.sleep(2000);
Stat stat = nozk.exists(PATH, false);
if (stat!=null) {
nozk.setData(PATH, prefix.getBytes(), -1);
System.out.println(prefix + "更新成功");
}
} catch (Exception e) {
System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
}
}
/**
* 更新数据:采用错误的密码
*/
static void updateDataByBadAuthentication() {
String prefix = "[使用错误的授权信息]";
System.out.println(prefix + "更新数据:" + PATH);
try {
ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
//授权
badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
Thread.sleep(2000);
Stat stat = badzk.exists(PATH, false);
if (stat!=null) {
badzk.setData(PATH, prefix.getBytes(), -1);
System.out.println(prefix + "更新成功");
}
} catch (Exception e) {
System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
}
}
/**
* 更新数据:采用正确的密码
*/
static void updateDataByCorrectAuthentication() {
String prefix = "[使用正确的授权信息]";
System.out.println(prefix + "更新数据:" + PATH);
try {
Stat stat = zk.exists(PATH, false);
if (stat!=null) {
zk.setData(PATH, prefix.getBytes(), -1);
System.out.println(prefix + "更新成功");
}
} catch (Exception e) {
System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
}
}
/**
* 不使用密码 删除节点
*/
static void deleteNodeByNoAuthentication() throws Exception {
String prefix = "[不使用任何授权信息]";
try {
System.out.println(prefix + "删除节点:" + PATH_DEL);
ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
Thread.sleep(2000);
Stat stat = nozk.exists(PATH_DEL, false);
if (stat!=null) {
nozk.delete(PATH_DEL,-1);
System.out.println(prefix + "删除成功");
}
} catch (Exception e) {
System.err.println(prefix + "删除失败,原因是:" + e.getMessage());
}
}
/**
* 采用错误的密码删除节点
*/
static void deleteNodeByBadAuthentication() throws Exception {
String prefix = "[使用错误的授权信息]";
try {
System.out.println(prefix + "删除节点:" + PATH_DEL);
ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
//授权
badzk.addAuthInfo(authentication_type,badAuthentication.getBytes());
Thread.sleep(2000);
Stat stat = badzk.exists(PATH_DEL, false);
if (stat!=null) {
badzk.delete(PATH_DEL, -1);
System.out.println(prefix + "删除成功");
}
} catch (Exception e) {
System.err.println(prefix + "删除失败,原因是:" + e.getMessage());
}
}
/**
* 使用正确的密码删除节点
*/
static void deleteNodeByCorrectAuthentication() throws Exception {
String prefix = "[使用正确的授权信息]";
try {
System.out.println(prefix + "删除节点:" + PATH_DEL);
Stat stat = zk.exists(PATH_DEL, false);
if (stat!=null) {
zk.delete(PATH_DEL, -1);
System.out.println(prefix + "删除成功");
}
} catch (Exception e) {
System.out.println(prefix + "删除失败,原因是:" + e.getMessage());
}
}
/**
* 使用正确的密码删除节点
*/
static void deleteParent() throws Exception {
try {
Stat stat = zk.exists(PATH_DEL, false);
if (stat == null) {
zk.delete(PATH, -1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、应用场景实例
当有多个客户端连接着zookeeper集群并且对zookeeper进行watch时,另外新增的客户端对zookeeper的操
作可以通知到之前对zookeeper进行watch的客户端。详细代码在cluster包下面。
五、zkClient客户端
1、基础API
package com.lptxyl.zkClient;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.ZkConnection;
public class ZkClientBase {
/** zookeeper地址 */
static final String CONNECT_ADDR = "192.168.1.103:2181,192.168.1.104:2181,192.168.1.105:2181";
/** session超时时间 */
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), 50000);
//1. create and delete方法
zkc.createEphemeral("/temp");
zkc.createPersistent("/super/c1", true);
Thread.sleep(10000);
// zkc.delete("/temp");
// zkc.deleteRecursive("/super");
//2. 设置path和data 并且读取子节点和每个节点的内容
// zkc.createPersistent("/super", "1234");
// zkc.createPersistent("/super/c1", "c1内容");
// zkc.createPersistent("/super/c2", "c2内容");
// List<String> list = zkc.getChildren("/super");
// for(String p : list){
// System.out.println(p);
// String rp = "/super/" + p;
// String data = zkc.readData(rp);
// System.out.println("节点为:" + rp + ",内容为: " + data);
// }
//3. 更新和判断节点是否存在
// zkc.writeData("/super/c1", "新内容");
// System.out.println(zkc.readData("/super/c1"));
// System.out.println(zkc.exists("/super/c1"));
//4.递归删除/super内容
// zkc.deleteRecursive("/super");
zkc.close();
}
}
2、watch模式
代码1:
package com.lptxyl.zkClient.watcher;
import java.util.List;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.ZkConnection;
public class ZkClientWatcher1 {
/** zookeeper地址 */
static final String CONNECT_ADDR = "192.168.1.103:2181,192.168.1.104:2181,192.168.1.105:2181";
/** session超时时间 */
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), 50000);
//对父节点添加监听子节点变化。
zkc.subscribeChildChanges("/super", new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println("parentPath: " + parentPath);
System.out.println("currentChilds: " + currentChilds);
}
});
Thread.sleep(3000);
zkc.createPersistent("/super");
Thread.sleep(1000);
zkc.createPersistent("/super" + "/" + "c1", "c1内容");
Thread.sleep(1000);
zkc.createPersistent("/super" + "/" + "c2", "c2内容");
Thread.sleep(1000);
zkc.delete("/super/c2");
Thread.sleep(1000);
zkc.deleteRecursive("/super");
Thread.sleep(Integer.MAX_VALUE);
}
}
代码2:
package com.lptxyl.zkClient.watcher;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.ZkConnection;
public class ZkClientWatcher2 {
/** zookeeper地址 */
static final String CONNECT_ADDR = "192.168.1.103:2181,192.168.1.104:2181,192.168.1.105:2181";
/** session超时时间 */
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), 5000);
zkc.createPersistent("/super", "1234");
//对父节点添加监听子节点变化。
zkc.subscribeDataChanges("/super", new IZkDataListener() {
@Override
public void handleDataDeleted(String path) throws Exception {
System.out.println("删除的节点为:" + path);
}
@Override
public void handleDataChange(String path, Object data) throws Exception {
System.out.println("变更的节点为:" + path + ", 变更内容为:" + data);
}
});
Thread.sleep(3000);
zkc.writeData("/super", "456", -1);
Thread.sleep(1000);
zkc.delete("/super");
Thread.sleep(Integer.MAX_VALUE);
}
}