zookeeper学习笔记
因最近工作中要用到zookeeper,故找来资料学习一番,为加强记忆,特做笔记如下:
笔记内容:
1、zookeeper背景
2、本地微集群配置
3、java api使用
4、几种常见使用场景
5、运维管理
6、自己的理解
-----------分割线之开始正文----------------------------------------------------------------------------------------------------
一、背景
(说实话,以下是我网上抄的,具体的理解在最后再写)ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。
二、本地伪集群配置
就是在本地起三个zookeeper服务,模拟zookeeper集群。在本地建三个文件夹,分别叫server1、server2跟server3。每一个其中都包含data、datalog跟zookeeper-3.4.6三个文件夹,data文件夹下建一名为myid的文件,内容分别为1,2,3。
zookeeper的conf文件夹下有三个配置文件,zoo_sample.cfg为zookeeper的模板配置文件。所需的配置一般可以从该文件中找到。在该文件夹下新建一配置文件叫zoo.cfg,内容为:
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/test/zookeepertest/server1/data
dataLogDir=/test/zookeepertest/server1/dataLog
clientPort=2181
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
注意:datadir、datalogdir跟clientport三项,在三个zookeeper配置文件中不同。
除了修改 zoo.cfg 配置文件,集群模式下还要配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面就有一个数据,就是 server.1中的1(server.2就是2,,,),Zookeeper 启动时会读取这个文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是那个 server。
dataDir跟dataLogDir的路径配置要正确,否则会启动失败,控制台或日志会打印该属性错误,找不到路径。windows下注意路径要双斜线。
参数说明:
tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。
dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
dataLogDir:顾名思义就是 Zookeeper 保存日志文件的目录
clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
initLimit:这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒
syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 2*2000=4 秒
启动跟简单查看:
切换到bin目录下,命令行执行./zkServer.sh start 启动zookeeper。启动第一个会报错,因为其它的都没有启动,检测不到其他zookeeper所致,启动第二个zookeeper后第一个报错会停止。
zookeeper启动后,可以通过telnet来检测是否启动成功:
显示connected to xxxxx. 则表示成功连接到zookeeper,也意味着zookeeper启动成功。
通过stat命令可以查看当前连接的zookeeper的状态:
mode:follower,我们可以知道当前连接的zookeeper为follower,也就是从机,如果是主机,mode的值应该是leader。
成功启动后,我们可以通过zookeeper自带的客户端进行一些简单的操作:
通过运行zkCli.sh可以打开自带客户端,随便输入,按回车,可以看到zookeeper支持的命令列表:
此时,可以通过ls /路径 查看路径目录下的节点内容,根目录为/
例如,我们可以通过ls / 查看根目录下节点内容,通过create /mynode myvalue 在根目录下创建mynode节点,节点的值为myvalue,查看某节点用get /路径
三、java api 使用
1、java与zookeeper建立连接:连接的建立过程是异步的,所以如果我们需要在连接建立后进行一些操作,则需要一个“返回函数”,该过程是由watcher类提供的process方法实现。代码如下:
1 public class CreateSession implements Watcher { 2 private static ZooKeeper zookeeper; 3 4 public static void main(String[] args) throws IOException, InterruptedException { 5 zookeeper = new ZooKeeper("127.0.0.1:2181",5000,new CreateSession()); 6 System.out.println(zookeeper.getState()); 7 Thread.sleep(Integer.MAX_VALUE); 8 } 9 10 private void doSomething(){ 11 System.out.println("do something"); 12 } 13 14 public void process(WatchedEvent event) { 15 System.out.println("收到事件:"+event); 16 if(event.getState() == KeeperState.SyncConnected){ 17 doSomething(); 18 } 19 } 20 21 }
通过代码测试,发现第7行在注释的情况下,只能输出connecting,
在不注释的情况下,输出
CONNECTING
收到事件:WatchedEvent state:SyncConnected type:None path:null
do something
反过来可以发现java通过new zookeeper建立的连接为异步的,代码会在连接没完成的情况下执行完毕,然后退出main方法,导致建立连接后的监听没有执行。
2、同步方式创建节点
直接创建节点,create方法的参数分别是:(节点路径,节点值(byte数组),节点权限设置,节点类型(临时节点,持久节点))
1 public class CreateNodeSync implements Watcher { 2 private static ZooKeeper zookeeper; 3 4 public static void main(String[] args) throws IOException, InterruptedException { 5 zookeeper = new ZooKeeper("127.0.0.1:2181",5000,new CreateNodeSync()); 6 System.out.println(zookeeper.getState()); 7 Thread.sleep(Integer.MAX_VALUE); 8 } 9 10 private void doSomething(){ 11 try { 12 String path = zookeeper.create("/node_42", "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 13 System.out.println("return path:" + path); 14 } catch (KeeperException e) { 15 // TODO Auto-generated catch block 16 e.printStackTrace(); 17 } catch (InterruptedException e) { 18 // TODO Auto-generated catch block 19 e.printStackTrace(); 20 } 21 System.out.println("do something"); 22 } 23 24 public void process(WatchedEvent event) { 25 System.out.println("收到事件:"+event); 26 if(event.getState() == KeeperState.SyncConnected){ 27 doSomething(); 28 } 29 } 30 31 }
3、异步方式创建节点
异步方式创建时,create方法需要额外两个参数,一个是一个StringCallback类(回调函数使用),一个是创建该节点时的上下文(当前上下文中需要回调函数中处理的一些内容)
需要注意的是,如果该节点已经存在,会创建失败,回调函数中rc的值会是-110。创建完成后,可以登录zkCli.sh查看节点内容进行校验,或者程序获取节点内容进行校验。
1 public class CreateNodeASync implements Watcher { 2 private static ZooKeeper zookeeper; 3 4 public static void main(String[] args) throws IOException, InterruptedException { 5 zookeeper = new ZooKeeper("127.0.0.1:2181",5000,new CreateNodeASync()); 6 System.out.println(zookeeper.getState()); 7 Thread.sleep(Integer.MAX_VALUE); 8 } 9 10 private void doSomething(){ 11 zookeeper.create("/node_55", "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT,new IStringCallback(),"创建"); 12 } 13 14 public void process(WatchedEvent event) { 15 System.out.println("收到事件:"+event); 16 if(event.getState() == KeeperState.SyncConnected){ 17 doSomething(); 18 } 19 } 20 21 static class IStringCallback implements AsyncCallback.StringCallback{ 22 23 public void processResult(int rc, String path, Object ctx, String name) { 24 StringBuilder sb = new StringBuilder(); 25 sb.append("rc="+rc).append("\n"); 26 sb.append("path="+path).append("\n"); 27 sb.append("ctx="+ctx).append("\n"); 28 sb.append("name="+name); 29 System.out.println(sb.toString()); 30 } 31 32 } 33 34 }
zookeeper的java api内容较多,不一一列举。修改、删除节点等操作均有同步跟异步两种方式,两者的主要区别就是异步方式多了一个回调函数,用于处理之后的业务操作。
使用场景部分,单独在下一篇进行记录。