4.1 IDEA环境搭建
新建project
将log4j.properties文件拷贝到项目的src目录
项目的根目录新建lib文件夹,将jar包拷贝到该目录下。
File-> ->Libaries
新建包
4.2 创建ZooKeeper客户端
在该包下新建类ZooKeeperTest
package com.bjsxt.api;
import java.io.IOException;
import java.util.List;
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.Ids;
import org.apache.ZooKeeper.ZooKeeper;
import org.apache.ZooKeeper.data.Stat;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ZooKeeperTest {
private static final int SESSION_TIMEOUT = 30000;
public static final Logger LOGGER = LoggerFactory.getLogger(ZooKeeperTest.class);
private Watcher watcher = new Watcher() {
public void process(WatchedEvent event) {
LOGGER.info("process : " + event.getType());
}
};
private ZooKeeper ZooKeeper;
/**创建ZooKeeper连接,单元测试前先执行该方法
* @throws IOException
*/
@Before
public void connect() throws IOException {
// indicate : all servers
ZooKeeper = new ZooKeeper(“192.168.20.52:2181,192.168.20.53:2181,192.168.20.54:2181”, SESSION_TIMEOUT, watcher);
}
/**测试完毕后关闭zk连接
*/
@After
public void close() {
try {
ZooKeeper.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 创建 znode
* 1.CreateMode
* PERSISTENT :持久化
* PERSISTENT_SEQUENTIAL
* EPHEMERAL :临时
* EPHEMERAL_SEQUENTIAL
* Access Control List: 访问控制列表
* https://baike.baidu.com/item/ACL/362453?fr=aladdin
* OPEN_ACL_UNSAFE: ANYONE CAN VISIT
*
------------------------------
*/
@Test
public void testCreate() {
String result = null;
try {
result = ZooKeeper.create("/zk001", "zk001data-p".getBytes(),
Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// result = ZooKeeper.create("/zk002", “zk002data-e”.getBytes(),
// Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
// Thread.sleep(30000);
} catch (Exception e) {
LOGGER.error(e.getMessage());
//抛出AssertionError
Assert.fail();
}
LOGGER.info(“create result : {}”, result);
}
/**
* 删除
*/
@Test
public void testDelete() {
try {
ZooKeeper.delete("/zk002", -1);
} catch (Exception e) {
LOGGER.error(e.getMessage());
//抛出AssertionError
Assert.fail();
}
}
/**
* 获取数据
*/
@Test
public void testGetData() {
String result = null;
try {
byte[] bytes = ZooKeeper.getData("/zk001", null, null);
result = new String(bytes);
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
LOGGER.info("getdata result------------------------------------------------- : {}", result);
}
/**查看从哪个zk服务器获取的数据,然后xshell关闭对应的zk服务器(zkServer.sh stop)
* 然后分析日志:
* @throws Exception
*/
@Test
public void testGetData01() throws Exception {
String result = null;
try {
byte[] bytes = ZooKeeper.getData("/zk001", null, null);
result = new String(bytes);
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
LOGGER.info("getdata result-----------------1------------------ : {}", result);
Thread.sleep(30000);
byte[] bytes;
try {
bytes = ZooKeeper.getData("/zk001", null, null);
result = new String(bytes);
} catch (KeeperException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
LOGGER.info("getdata result-----------------2-------------------- : {}", result);
}
/**
* 注册
*/
@Test
public void testGetDataWatch() {
String result = null;
try {
System.out.println("get:");
byte[] bytes = ZooKeeper.getData("/zk001", new Watcher() {
public void process(WatchedEvent event) {
LOGGER.info("testGetDataWatch watch : {}", event.getType());
System.out.println("watcher ok");
//testGetDataWatch();
}
}, null);
result = new String(bytes);
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
LOGGER.info("getdata result------------------------------------------ : {}", result);
// wacth NodeDataChanged
try {
System.out.println("set:");
ZooKeeper.setData("/zk001", "testSetDataWAWWW".getBytes(), -1);
System.out.println("set2:");
ZooKeeper.setData("/zk001", "testSetDataWAWWW".getBytes(), -1);
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
System.out.println("over");
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test
public void testExists() {
Stat stat = null;
try {
stat = ZooKeeper.exists("/zk001", false);
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
Assert.assertNotNull(stat);
LOGGER.info("exists result : {}", stat.getCzxid());
}
@Test
public void testSetData() {
Stat stat = null;
try {
stat = ZooKeeper.setData("/zk001", "testSetData".getBytes(), -1);
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
Assert.assertNotNull(stat);
LOGGER.info("exists result : {}", stat.getVersion());
}
@Test
public void testExistsWatch1() {
Stat stat = null;
try {
stat = ZooKeeper.exists("/zk001", true);
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
Assert.assertNotNull(stat);
try {
ZooKeeper.delete("/zk001", -1);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testExistsWatch2() {
Stat stat = null;
try {
stat = ZooKeeper.exists("/zk002", new Watcher() {
@Override
public void process(WatchedEvent event) {
LOGGER.info("testExistsWatch2 watch : {}", event.getType());
}
});
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
Assert.assertNotNull(stat);
try {
ZooKeeper.setData("/zk002", "testExistsWatch2".getBytes(), -1);
} catch (Exception e) {
e.printStackTrace();
}
try {
ZooKeeper.delete("/zk002", -1);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*/
@Test
public void testGetChild() {
try {
ZooKeeper.create("/zk/001", "001".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
ZooKeeper.create("/zk/002", "002".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
List list = ZooKeeper.getChildren("/zk", true);
for (String node : list) {
LOGGER.info("fffffff {}", node);
}
} catch (Exception e) {
LOGGER.error(e.getMessage());
Assert.fail();
}
}
}
框架实现的客户端和服务器之间的故障转移过程
注册Watcher,查询注册watch,增删改触发watcher
如果是多次增删改,回调方法调用几次?
1、watcher事件是一次性的
2、是增删改触发watcher,但是watcher是线程异步执行
3、watcher可以反复注册
如何平滑反复注册?在回调方法中迭代调用即可。
5 分布式协调案例
如何实现“跨虚拟机”的调用,它就是 RMI(Remote Method Invocation,远程方法调用)。例如,服务A 在 JVM1 中运行,服务B 在 JVM2 中运行,服务A 与 服务B 可相互进行远程调用,就像调用本地方法一样,这就是 RMI。在分布式系统中,我们使用 RMI 技术可轻松将 服务提供者(Service Provider)与 服务消费者(Service Consumer)进行分离,充分体现组件之间的弱耦合,系统架构更易于扩展。
我们先从通过一个最简单的 RMI 服务与调用示例,快速掌握 RMI 的使用方法,然后指出 RMI 的局限性,最后笔者对此问题提供了一种简单的解决方案,即使用 ZooKeeper 轻松解决 RMI 调用过程中所涉及的问题。