要面试才学的zookeeper+dubbo,搞起
Zookeeper
ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列、分布式通知/协调等
基础数据有4种类型:(-s 有序 -e 临时)
长久有序节点
临时有序节点
长久无序节点
临时有序节点
客户端基础命令
./zkServer.sh start 启动
./zkServer.sh restart 重启
./zkServer.sh stop 关闭
./zkCli.sh -server 127.0.0.1:2182 客户端通过ip连接服务器
addauth scheme(digest|auth) auth //输入认证授权信息 添加用户以及密码到认证库
close
config [-c] [-w] [-s]
connect host:port
create [-s] [-e] [-c] [-t ttl] path [data] [acl] //创建节点
#默认创建的就是持久节点
create /test
#创建序号节点
create -s /test
#创建临时节点, 断开会话 在连接将会自动删除
create -e /temp
#临时序号节点
create -e -s /temp/seq
delete [-v version] path //删除版本号为xx的节点
deleteall path [-b batch size]
delquota [-n|-b] path
get [-s] [-w] path // get -w /xx 给xx节点设置watch时间 get -s /xx 获取xx详情 父节点添加watch时间
getAcl [-s] path //获取节点得acl权限信息
getAllChildrenNumber path
getEphemerals path
history
listquota path
ls [-s] [-w] [-R] path //查看下面的节点 子节点添加watch时间
printwatches on|off
quit
reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
redo cmdno
removewatches path [-c|-d|-a] [-l]
set [-s] [-v version] path data //更新版本号为xx的节点
setAcl [-s] [-v version] [-R] path acl 设置节点得acl权限信息
setquota -n|-b val path
stat [-w] path //获取节点信息状态
sync path
version
zookeeper提供的Java原生API(复制自己玩一下)
package com.exampletext.demo.zookeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.CountDownLatch;
/**
* zookeeper原生API
*/
public class zookeeperTest {
public static void main(String[] args) throws IOException, InterruptedException, KeeperException, NoSuchAlgorithmException {
CountDownLatch countDownLatch = new CountDownLatch(1);
String path="192.168.9.148:2181";
//String path="192.168.43.46";
ZooKeeper zooKeeper=new ZooKeeper(path, 2000000,new myWatcher());
Thread.sleep(2000);
long sessionId = zooKeeper.getSessionId();
byte[] sessionPasswd = zooKeeper.getSessionPasswd();
System.out.println(zooKeeper.getSessionId());
System.out.println(zooKeeper.getState());
Thread.sleep(2000);
//zooKeeper.create("/zookeeper/java","123".getBytes(), Arrays.asList(), CreateMode.PERSISTENT);
// System.out.println("准备重连");
// ZooKeeper zooKeepe2r=new ZooKeeper(path, 2000000,new myWatcher(),sessionId,sessionPasswd);
// Thread.sleep(2000);
// System.out.println(zooKeeper.getSessionId());
// System.out.println(zooKeeper.getState());
//1.创建节点
// zooKeeper.create("/zookeeper/mycallback", //节点
// "123".getBytes(),//数据
// ZooDefs.Ids.OPEN_ACL_UNSAFE,//权限
// CreateMode.PERSISTENT,new myZKCallback(),//回调函数
// "传给你回调");//传给回调函数的值
// Thread.sleep(2000);
//2.获取节点
// byte[] data = zooKeeper.getData("/zookeeper/callback", new myWatcher(countDownLatch), new Stat());
//
// System.out.println(new String(data));
// countDownLatch.await();
// //3.修改节点
// Stat stat = zooKeeper.setData("/zookeeper/callback", "bbb".getBytes(), 3);
// System.out.println(stat.getVersion());
// //4.删除节点
// zooKeeper.delete("/zookeeper/callback",stat.getVersion());
//5、获取子节点
// List<String> childrens = zooKeeper.getChildren("/zookeeper",true);
// for (String children : childrens) {
// System.out.println(children);
// }
//List<String> children = zooKeeper.getChildren("/zookeeper/callback", new myWatcher(countDownLatch), new Stat());
//6、判断节点是否存在
// Stat stat = zooKeeper.exists("/zookeeper/nnnn", true);
// if(stat==null){
// System.out.println("是空!!!");
// }
// System.out.println(stat);
//创建用户权限节点
// List<ACL> aclList = new ArrayList<>();
// String adminPassword = DigestAuthenticationProvider.generateDigest("admin:admin");
// ACL acl = new ACL(ZooDefs.Perms.ALL,new Id("digest",adminPassword ));
// aclList.add(acl);
// String s = zooKeeper.create("/zookeeper/myuser", "2121".getBytes(), aclList, CreateMode.PERSISTENT);
// zooKeeper.addAuthInfo("digest","admin:admin".getBytes());
// byte[] data = zooKeeper.getData("/zookeeper/myuser", new myWatcher(), new Stat());
//
// System.out.println(new String(data));
}
}
重点使用 apache封装的curator命令
public class curatorTest {
private CuratorFramework curatorFramework;
//private static final String path="192.168.43.46";
private static final String path="192.168.9.148:2181";
public CuratorFramework client=null;
curatorTest() {
//初始sleep时间,最大重试次数,最大重试时间
//RetryPolicy retryPolicy=new ExponentialBackoffRetry(1000,3,5000);
//重试3次,最大
RetryPolicy retryPolicy=new RetryNTimes(3,5000);
//curatorFramework.create().forPath(path)
this.client = CuratorFrameworkFactory.builder()
.connectString(path)
.sessionTimeoutMs(10000)
.retryPolicy(retryPolicy)
//.namespace("curatorFather") //命名空间 指定头节点,如果不指定,后面创建的节点都是以头节点开始
.build();
this.client.start();
}
public static void main(String[] args) throws Exception {
curatorTest a=new curatorTest();
System.out.println("连接---------");
System.out.println(a.client.getState());
boolean started = a.client.isStarted();
System.out.println("状态"+started);
//增
// a.client.create()
// .creatingParentsIfNeeded()
// .withMode(CreateMode.PERSISTENT)
// .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
// .forPath("/mycurator/testa/a/b/c/1/2/3","123".getBytes());
//改
// a.client.setData()
// .withVersion(0) //版本
// .forPath("/mycurator/testa","456".getBytes());
//删除
a.client.delete()
.guaranteed() //确保能删除
.deletingChildrenIfNeeded()
.withVersion(0) //版本
.forPath("/dubbo");
//读取节点信息
// Stat stat=new Stat();
// byte[] data = a.client.getData()
// .storingStatIn(stat)
// .forPath("/mycurator");
// System.out.println("-----------"+new String(data));
// System.out.println(stat.getVersion());
//读取子节点
// List<String> childNodes = a.client.getChildren().forPath("/mycurator");
// System.out.println("打印子节点------------");
// for (String childNode : childNodes) {
// System.out.println(childNode);
// }
//判断是否存在
// Stat stat = a.client.checkExists().forPath("/mycurator/c");
// if(stat==null){
// System.out.println("不存在");
// }
// System.out.println(stat);
//设置监听 和原生API一样 只监听一次
// a.client.getData().usingWatcher(new myWatcher()).forPath("/mycurator");
//curator提供一次注册,n次监听
// NodeCache nodeCache=new NodeCache(a.client, "/mycurator");
// nodeCache.start(true);//是否获取该节点的值
// if(nodeCache.getCurrentData()!=null){
// System.out.println("初始化节点为:"+new String(nodeCache.getCurrentData().getData()));
// }else {
// System.out.println("初始化节点为空");
// }
// nodeCache.getListenable().addListener(new NodeCacheListener() {
// @Override
// public void nodeChanged() throws Exception {
// if(nodeCache.getCurrentData()!=null){
// System.out.println("节点路径:"+nodeCache.getPath()+new String(nodeCache.getCurrentData().getData()));
// }else {
// System.out.println("节点不存在了");
// }
// }
// });
//监听父节点
//StartMode 初始化方式
/**
* POST_INITIALIZED_EVENT :异步初始化,初始化之后会触发
* NORMAL:异步初始化
* BUILD_INITIAL_CACHE:同步初始化
*/
//
Thread.sleep(10000000);
System.out.println("关闭---------");
a.client.close();
System.out.println("状态"+a.client.isStarted());
}
}
自己的watcher类
public class myWatcher implements Watcher {
private CountDownLatch countDownLatch;
public myWatcher( ){
}
public myWatcher(CountDownLatch countDownLatch){
this.countDownLatch=countDownLatch;
}
@Override
public void process(WatchedEvent event) {
System.out.println("watcher获取状态"+event.getState());
System.out.println("watcher获取状态"+event);
System.out.println("收到回调函数!!!!!!!!!!");
if(Event.EventType.NodeCreated.equals(event.getType()) ){
System.out.println("是创建新的节点"+ event.getPath());
}else if(Event.EventType.NodeDataChanged.equals(event.getType())){
System.out.println("是更改节点"+ event.getPath());
}else if(Event.EventType.NodeChildrenChanged.equals(event.getType())){
System.out.println("是更改子节点"+ event.getPath());
}else if(Event.EventType.NodeDeleted.equals(event.getType())){
System.out.println("节点被删除"+ event.getPath());
}
if(countDownLatch!=null){
countDownLatch.countDown();
}
}
}
自己的回调函数(java基础API有提供回调函数 )
public class myZKCallback implements AsyncCallback.StringCallback {
@Override
public void processResult(int rc, String path, Object ctx, String name) {
System.out.println("回调函数!!!"+rc);
System.out.println("回调函数!!!"+path);
System.out.println("回调函数!!!"+ctx);
System.out.println("回调函数!!!"+name);
}
}
重点提一下
zookeeper中watcher机制在zookeeper中只能触发一次。但是apache封装的curator提供了一次注册,多次监听的方式。包括 NodeCache 以及子节点 PathChildrenCache的方式。正因为机制,我们可以通过监听一个节点得变化,可以实现zookeeper动态更新配置的,分布式锁等等。
分布式锁
锁服务可以分为两类,一个是保持独占,另一个是控制时序。
对于第一类,我们将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。
对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除,依次方便
zookeeper的ZAB协议(恢复模式和广播模式)
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。
恢复模式:当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。