1.首先,先了解下zookeeper吧,这篇文章总结的很好:【分布式】Zookeeper应用场景
2.那么,接下来就是在项目中引入依赖包:Zookeeper依赖包
3.把Log4j也配置一下,方便调试:
### set log levels ###
log4j.rootLogger=INFO,console
#log4j.logger.com.neu.dao.IStudentDao=trace,console
### console ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#log4j.appender.console.layout.ConversionPattern=[%-5d][%d{yyyy-MM-dd HH\:mm\:ss}] %c %L %m%n
log4j.appender.console.layout.ConversionPattern=%5p [%t] - %m%n
4.Curator的测试:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class test implements Watcher {
@Override
public void process(WatchedEvent watchedEvent) {
// TODO Auto-generated method stub
System.out.println("接收到watch通知:{}" + watchedEvent);
}
private static final Logger logger = LoggerFactory.getLogger(test.class);
public static void main(String[] args) throws UnsupportedEncodingException, Exception {
CuratorFramework curator = CuratorFrameworkFactory.newClient("bigdata01:2181", 5000, 3000,
new RetryNTimes(5, 1000));
curator.start();
String regContent = "192.168.88.58:9080";
String zkRegPathPrefix = "/curator/service-provider-";
// TODO:
MyConnectionStateListener stateListener = new MyConnectionStateListener(zkRegPathPrefix, regContent);
curator.getConnectionStateListenable().addListener(stateListener);
curator.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(zkRegPathPrefix,
regContent.getBytes("UTF-8"));
System.out.println("状态:" + curator.getState());
System.out.println("存在:" + zkRegPathPrefix + regContent.getBytes("UTF-8") + " , "
+ curator.checkExists().forPath(zkRegPathPrefix + regContent.getBytes("UTF-8")));
System.out.println("---------------------");
}
}
输出:
状态:STARTED
INFO [main-EventThread] - State change: CONNECTED
存在:/curator/service-provider-[B@3b088d51 , null
---------------------
接下来的test也是分别放入上面的test类就可以了。
5.建立客户端与zk服务端的连接:
// 建立客户端与zk服务端的连接
@Test
public void test01() throws IOException, InterruptedException {
// 实例化zookeeper客户端
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
System.out.println("客户端开始连接zookeeper服务器...");
System.out.println("连接状态:{}" + zooKeeper.getState());
// 避免发出连接请求就断开,不然就无法正常连接也无法获取watch事件的通知
Thread.sleep(2000);
System.out.println("连接状态:{}" + zooKeeper.getState());
}
输出:
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
连接状态:{}CONNECTED
6.zk会话重连机制:
// zk会话重连机制
@Test
public void test02() throws IOException, InterruptedException {
// 实例化zookeeper客户端
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
logger.warn("客户端开始连接zookeeper服务器...");
logger.warn("连接状态:{}", zooKeeper.getState());
Thread.sleep(2000);
logger.warn("连接状态:{}", zooKeeper.getState());
// 记录本次会话的sessionId
long sessionId = zooKeeper.getSessionId();
// 转换成16进制进行打印
logger.warn("sid:{}", "0x" + Long.toHexString(sessionId));
// 记录本次会话的session密码
byte[] sessionPassword = zooKeeper.getSessionPasswd();
Thread.sleep(200);
// 开始会话重连
logger.warn("开始会话重连...");
// 加上sessionId和password参数去实例化zookeeper客户端
ZooKeeper zkSession = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test(), sessionId, sessionPassword);
logger.warn("重新连接状态zkSession:{}", zkSession.getState());
Thread.sleep(2000);
logger.warn("重新连接状态zkSession:{}", zkSession.getState());
}
输出:
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
WARN [main] - 连接状态:CONNECTED
WARN [main] - sid:0x3660e6e1bdb9a51
WARN [main] - 开始会话重连...
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
接收到watch通知:{}WatchedEvent state:Disconnected type:None path:null
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
WARN [main] - 重新连接状态zkSession:CONNECTED
7.创建zk节点:
// 创建zk节点
@Test
public void test03() throws IOException {
String path = "/zc";
byte[] data = "zc-data".getBytes();
List<ACL> acls = ZooDefs.Ids.OPEN_ACL_UNSAFE;
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
String result = "";
try {
/**
* 同步或者异步创建节点,都不支持子节点的递归创建,异步有一个callback函数 参数: path:节点创建的路径
* data:节点所存储的数据的byte[] acl:控制权限策略 Ids.OPEN_ACL_UNSAFE -->
* world:anyone:cdrwa CREATOR_ALL_ACL --> auth:user:password:cdrwa
* createMode:节点类型, 是一个枚举 PERSISTENT:持久节点
* PERSISTENT_SEQUENTIAL:持久顺序节点 EPHEMERAL:临时节点
* EPHEMERAL_SEQUENTIAL:临时顺序节点
*/
// 同步创建zk节点,节点类型为临时节点
result = zooKeeper.create(path, data, acls, CreateMode.EPHEMERAL);
System.out.println("创建节点:\t" + result + "\t成功...");
Thread.sleep(2000);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
输出:
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
创建节点: /zc 成功...
8.修改zk节点数据:
// 修改zk节点数据
@Test
public void test04() throws KeeperException, InterruptedException, IOException {
test03();
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
Stat status = zooKeeper.setData("/zc", "this is new data".getBytes(), 0);
// 通过Stat对象可以获取znode所有的状态属性,这里以version为例
System.out.println("修改成功,当前数据版本为:" + status.getVersion());
}
输出:
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
创建节点: /zc 成功...
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
修改成功,当前数据版本为:1
9.删除zk节点:
// 删除zk节点
@Test
public void test05() throws IOException, KeeperException, InterruptedException{
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
zooKeeper.create("/zc", "test-delete-data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Thread.sleep(1000);
zooKeeper.delete("/zc", 0);
zooKeeper.close();
}
10.获取zk节点数据:
// 获取zk节点数据
@Test
public void test06() throws KeeperException, InterruptedException, IOException {
test03();
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
byte[] resByte = zooKeeper.getData("/zc", true, new Stat());
String result = new String(resByte);
System.out.println("/zc 节点的数据: " + result);
zooKeeper.close();
}
输出:
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
/zc 节点的数据: zc-data
11.获取zk子节点列表:
// 获取zk子节点列表
@Test
public void test07() throws IOException, KeeperException, InterruptedException {
test03();
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
List<String> strChildList = zooKeeper.getChildren("/zc", false);
for (String s : strChildList) {
System.out.println(s);
}
}
12.判断zk节点是否存在:
// 判断zk节点是否存在
@Test
public void test08() throws IOException, KeeperException, InterruptedException {
test03();
ZooKeeper zooKeeper = new ZooKeeper(CONNECT_ADDR, SESSION_TIMEOUT, new test());
Stat stat = zooKeeper.exists("/zc", true);
if (stat != null) {
System.out.println("testNode 节点存在...");
System.out.println("该节点的数据版本为:" + stat.getVersion());
} else {
System.out.println("该节点不存在...");
}
}
输出:
接收到watch通知:{}WatchedEvent state:SyncConnected type:None path:null
testNode 节点存在...
该节点的数据版本为:0
注意:如果想要通过zookeeper来实时的检测节点是否存在,用它的异步通知机制。不同机器间需要检测到彼此是否在正常运行,可以使用Zookeeper实现机器间的心跳检测,基于其临时节点特性(临时节点的生存周期是客户端会话,客户端若宕机后,其临时节点自然不再存在),可以让不同机器都在Zookeeper的一个指定节点下创建临时子节点,不同的机器之间可以根据这个临时子节点来判断对应的客户端机器是否存活。