zookeeper学习

主要的理论内容在这里:

http://blog.csdn.net/xinguan1267/article/details/38422149


关键有几个知识点:

1、session:client与server之间的连接,超时

2、znode:zookeeper的文件储存格式(inode23333),数据大小(1M),权限控制(ACL),模式:(持久或者session消失就没了),version,cversion,czxid,mzxid,pzxid

3、基本架构:一个leader,多个follower,Observer

4、读写过程:写过程:2次网络IO,一次硬盘IO,读过程:不需要经过leader

5、特性:写log,线性化,FIFO

6、api说明:


接下来是一个应用zookeeper的小demo


/**
 * Created by wangjian36 on 17/1/19.
 */
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;

/**
 *
 * @author http://blog.csdn.net/java2000_wl 
 * @version 1.0 
 */
public class ZookeeperTest {

    private static final int SESSION_TIMEOUT = 30000;
    

    private Watcher watcher =  new Watcher() {

        public void process(WatchedEvent event) {
            System.out.println("process : " + event.getType());
            if(Event.KeeperState.SyncConnected == event.getState()){
                connectedSemaphore.countDown();
            }
        }
    };

    private ZooKeeper zooKeeper;
    private CountDownLatch connectedSemaphore = new CountDownLatch(1);
    /**
     *  连接zookeeper 
     * 
------------------------------
* @throws IOException */ public void connect() throws IOException, InterruptedException { zooKeeper = new ZooKeeper("localhost:2181", SESSION_TIMEOUT, watcher); connectedSemaphore.await(); } Semaphore semaphore = new Semaphore(1); public void connectWithLock() throws IOException, InterruptedException { semaphore.acquire(); zooKeeper = new ZooKeeper("localhost:2181", SESSION_TIMEOUT, new Watcher() { @Override public void process(WatchedEvent event) { System.out.println("connection started"); semaphore.release(); } }); semaphore.acquire(); } /** * 关闭连接 *
------------------------------
*/ public void close() { try { zooKeeper.close(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 创建一个znode * 1.CreateMode 取值 * PERSISTENT:持久化,这个目录节点存储的数据不会丢失 * PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名; * EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session过期超时,这种节点会被自动删除 * EPHEMERAL_SEQUENTIAL:临时自动编号节点 *
------------------------------
*/ public void testCreate(String path,String data) throws KeeperException, InterruptedException { String result = null; result = zooKeeper.create(path, data.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode .PERSISTENT); System.out.println("create result : {}"+result); } /** * 删除节点 忽略版本 *
------------------------------
*/ public void testDelete(String path) { try { zooKeeper.delete(path, -1); } catch (Exception e) { } } /** * 获取数据 *
------------------------------
*/ public void testGetData(String path) throws KeeperException, InterruptedException { String result = null; Stat stat = new Stat(); byte[] bytes = zooKeeper.getData(path, null, stat); result = new String(bytes); System.out.println("getdata result : "+result+"\nstat_children "+stat.getNumChildren()); } /** * 获取数据 设置watch *
------------------------------
*/ public void testGetDataWatch(String path) { String result = null; try { byte[] bytes = zooKeeper.getData(path, new Watcher() { public void process(WatchedEvent event) { System.out.println("testGetDataWatch watch : {}"+event.getType()); } }, null); result = new String(bytes); } catch (Exception e) { } System.out.println("getdata result : {}"+result); } /** * 判断节点是否存在 * 设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper实例时指定的 watcher *
------------------------------
*/ public Stat testExists(String path) { Stat stat = null; try { stat = zooKeeper.exists(path, false); } catch (Exception e) { } System.out.println("exists result : {}"+stat.getCzxid()); return stat; } /** * 设置对应znode下的数据 , -1表示匹配所有版本 *
------------------------------
*/ public void testSetData(String path) { Stat stat = null; try { stat = zooKeeper.setData(path, "testSetData".getBytes(), -1); } catch (Exception e) { } System.out.println("exists result : {}"+ stat.getVersion()); } /** * 判断节点是否存在, * 设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper实例时指定的 watcher *
------------------------------
*/ public void testExistsWatch1(String path) { Stat stat = null; try { stat = zooKeeper.exists(path, true); } catch (Exception e) { } try { zooKeeper.delete(path, -1); } catch (Exception e) { e.printStackTrace(); } } /** * 判断节点是否存在, * 设置监控这个目录节点的 Watcher *
------------------------------
*/ public void testExistsWatch2(String path) { Stat stat = null; try { stat = zooKeeper.exists(path, new Watcher() { @Override public void process(WatchedEvent event) { System.out.println("testExistsWatch2 watch : {}"+event.getType()); } }); } catch (Exception e) { } // 触发watch 中的process方法 NodeDataChanged try { zooKeeper.setData("/zk002", "testExistsWatch2".getBytes(), -1); } catch (Exception e) { e.printStackTrace(); } // 不会触发watch 只会触发一次 try { zooKeeper.delete("/zk002", -1); } catch (Exception e) { e.printStackTrace(); } } /** * 获取指定节点下的子节点 *
------------------------------
*/ 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) { System.out.println("node {}"+node); } } catch (Exception e) { } } public static void main(String args[]) throws IOException, KeeperException, InterruptedException { ZookeeperTest zookeeperTest = new ZookeeperTest(); zookeeperTest.connectWithLock(); //zookeeperTest.testCreate("/java_test/test","Hello_Zookeeper"); Stat stat = zookeeperTest.testExists("/java_test/test"); if(stat!=null) zookeeperTest.testGetData("/java_test"); } }



这里,需要注意,在连接的时候,需要有一个CountDownLatch的对象,连接完成之后先await(),在watcher里处理的时候,调用countdown(),CountDownLatch对象,new出来的时候带一个数字,调用await()的时候把当先线程阻塞,然后当countDown,里面的counter到0的时候,阻塞的线程才能被唤醒。

之所以必须要加这块东西,主要是因为链接服务器是一个比较慢的过程,如果还没链接到服务器上,结果就要对文件进行操作,那就会导致error,因此必须将链接服务器的函数,在服务器确定能够链接上,返回一个watcher信息的时候,才唤醒链接函数,这样才能保证当connect函数结束的时候,一定链接上了服务器。


类似的同步方法应该都可以的。

我自己拿信号量实现了一个,不过很不优雅。



你可能感兴趣的:(分布式系统)