《分布式_Zookeeper》_Zookeeper原生API实现配置中心

Zookeeper在实际使用场景很多,比如配置中心,分布式锁,注册中心等。先简单用原生api搞个zookeeper的配置中心demo,原理是利用watcher 和 znode,客户端监听服务的znode变化

简单流程

image.png

相关代码

package com.huey.demo.configdemo;

/**
* @author huey China.
* @Description : zk 配置相关
* @Date Created in 2018/11/18 上午10:18
*/
public class ZookeeperConfig {

    protected String connectString="192.168.59.2:2181,192.168.59.3:2181,192.168.59.4:2181";

}

package com.huey.demo.configdemo;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

/**
* @author huey China.
* @Description : 配置中心服务端
* @Date Created in 2018/11/18 上午10:24
*/
public class ZookeeperConfigServerHandler extends ZookeeperConfig{

    private ZooKeeper zookeeper;

    public ZookeeperConfigServerHandler() {
        try {
            this.zookeeper = new ZooKeeper(connectString, 5000,null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /***
     * 创建持久节点
     * @param path
     * @param data
     * @return
     */
    public String createPersistent(String path,String data){
        try {
            return  zookeeper.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return  null;
    }


    /***
     * 创建临时节点
     * @param path
     * @param data
     * @return
     */
    public String createEphemeral(String path,String data){
        try {
            return  zookeeper.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return  null;
    }

    /***
     * 更新信息
     * @param path
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public String getData(String path,boolean watcher) throws KeeperException, InterruptedException {
        byte data[] = zookeeper.getData(path,watcher,null);
        data = (data == null)? "null".getBytes() : data;
        return new String(data);
    }


    /***
     * 更新信息
     * @param path
     * @param data
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public Stat setData(String path, String data) throws KeeperException, InterruptedException {
        return zookeeper.setData(path, data.getBytes(), -1);
    }

    /***
     * 是否存在
     * @param path
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public Stat exists(String path, boolean watcher) throws KeeperException, InterruptedException {
        return zookeeper.exists(path,watcher);

    }


    /***
     * 删除
     * @param path
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public void delete(String path) throws KeeperException, InterruptedException {
        zookeeper.delete(path,-1);
    }
    /***
     * 删除
     * @param path
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    public void deleteRecursive(String path) throws KeeperException, InterruptedException {
        ZKUtil.deleteRecursive(zookeeper, path);
    }

    public void close() throws InterruptedException {
        zookeeper.close();
    }


}
package com.huey.demo.configdemo;


import org.apache.zookeeper.KeeperException;
import org.junit.Before;
import org.junit.Test;

import java.util.UUID;

/**
* @author huey China.
* @Description : 模拟服务端 znode存储与修改
* @Date Created in 2018/11/18 上午11:00
*/

public class ZookeeperConfigServer {

    /**
    * 模拟某个节点存储机制
    *
    */
    private String path = null;
    private String pathValue = null;
    private ZookeeperConfigServerHandler zookeeperConfigServerHandler;


    /**
    * @author huey China.
    * @Description : 节点生成
    * @Date Created in 2018/11/18 上午11:01
    */
    @Before
    public void front() {
        String i = "1";
        this.path = new StringBuilder().append("/config_node").toString();
        /**
         *
         *sell_number_version
         */
        this.pathValue = new StringBuilder().append("/sell_").append(i).append("_").append(2).toString();
        System.out.println(this.path+ " ----->  " + this.pathValue);
    }


    /**
    * @author huey China.
    * @Description : 启动并创建临时节点
    * @Date Created in 2018/11/18 上午11:31 异常为事件未watch可忽略
    */
    @Test
    public void testCreate() throws InterruptedException {


        //启动服务端
        zookeeperConfigServerHandler = new ZookeeperConfigServerHandler();
      zookeeperConfigServerHandler.createEphemeral(this.path,this.pathValue);
      Thread.sleep(Integer.MAX_VALUE);
    }

    /**
    * @author huey China.
    * @Description : 模拟服务端修改节点数据
    * @Date Created in 2018/11/18 上午11:32
    */
    @Test
    public void testUpdate() throws InterruptedException, KeeperException {
        ZookeeperConfigServerHandler zookeeperConfigServerHandler = new ZookeeperConfigServerHandler();
        zookeeperConfigServerHandler.setData(this.path, new StringBuilder().append("/sell_").append(UUID.randomUUID()).append("_").append(System.currentTimeMillis()).toString());
    }

    /**
    * @author huey China.
    * @Description : 服务端获取该临时即诶单数据
    * @Date Created in 2018/11/18 上午11:33
    */
    @Test
    public  void testGetData() throws KeeperException, InterruptedException {
        System.out.println("zkconfig new value is " + zookeeperConfigServerHandler.getData(this.path,true));
    }
}
package com.huey.demo.configdemo;
/**
* @author huey China.
* @Description : zk watcher
* @Date Created in 2018/11/18 下午3:48
*/
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.ConcurrentHashMap;

public class ZookeeperConfigClientHandler extends ZookeeperConfig implements Watcher{

   private ZooKeeper zookeeper;
   /**
   *
   *该节点jvm内存存储
   */
   private ConcurrentHashMap<String, String> nodes = new ConcurrentHashMap<String, String>();

   public ConcurrentHashMap<String, String> getNodes() {
      return nodes;
   }

   public ZookeeperConfigClientHandler() {
      try {
         this.zookeeper = new ZooKeeper(connectString, 5000,this);
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public ZookeeperConfigClientHandler(String path) {
      try {
         this.zookeeper = new ZooKeeper(connectString, 5000,this);
      } catch (Exception e) {
         e.printStackTrace();
      }
   }




   /***
    * 创建临时节点
    * @param path
    * @param data
    * @return
    */
   public String createEphemeral(String path,String data){
      try {
         return  zookeeper.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
      } catch (KeeperException e) {
         e.printStackTrace();
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
      return  null;
   }

   /***
    * 获取信息
    * @param path
    * @return
    * @throws KeeperException
    * @throws InterruptedException
    */
   public String getData(String path,boolean watcher) throws KeeperException, InterruptedException {
      byte data[] = zookeeper.getData(path,watcher,null);
      data = (data == null)? "null".getBytes() : data;
      return new String(data);
   }


   /***
    * 更新信息
    * @param path
    * @param data
    * @return
    * @throws KeeperException
    * @throws InterruptedException
    */
   public Stat setData(String path, String data) throws KeeperException, InterruptedException {
      return zookeeper.setData(path, data.getBytes(), -1);
   }

   /***
    * 是否存在
    * @param path
    * @return
    * @throws KeeperException
    * @throws InterruptedException
    */
   public Stat exists(String path, boolean watcher) throws KeeperException, InterruptedException {
      return zookeeper.exists(path,watcher);

   }


   /***
    * 删除
    * @param path
    * @return
    * @throws KeeperException
    * @throws InterruptedException
    */
   public void delete(String path) throws KeeperException, InterruptedException {
      zookeeper.delete(path,-1);
   }
   /***
    * 删除
    * @param path
    * @return
    * @throws KeeperException
    * @throws InterruptedException
    */
   public void deleteRecursive(String path) throws KeeperException, InterruptedException {
      ZKUtil.deleteRecursive(zookeeper, path);
   }

   public void close() throws InterruptedException {
      zookeeper.close();
   }


   /**
   * @author huey China.
   * @Description : TODO 节点未动态化
   * @Date Created in 2018/11/18 上午11:44
   */
   public void process(WatchedEvent event) {
      // 连接状态
      Event.KeeperState keeperState = event.getState();
      // 事件类型
      Event.EventType eventType = event.getType();
      // 受影响的path
      String pathNode = event.getPath();

      System.out.println("连接状态:"+keeperState+",事件类型:"+eventType+",受影响的path:" + pathNode);

      try {
         String path = "/config_node";
         String data = this.getData(path, true);
         if(null!=this.exists(path,true) ) {
            nodes.put(path,data);
            System.out.println("zk内容:"+ data + ",内存内容:"+ nodes.get(path));
         }
         if (this.isNodeDataChanged(eventType, true)) {
            System.out.println("更改后zk内容:"+ this.getData(path, true) +  ",内存内容:"+ nodes.get(path));
         }

      } catch (Exception e) {
         e.printStackTrace();
      }
      System.out.println("--------------------");
   }

   /**
   * @author huey China.
   * @Description : 是否需要节点数据改变事件
   * @Date Created in 2018/11/18 上午11:46
   */
   private boolean isNodeDataChanged(Watcher.Event.EventType eventType,boolean flag){
      if (Event.EventType.NodeDataChanged == eventType && flag == true){
         return true;
      }
      return false;
   }
}
package com.huey.demo.configdemo;


import org.apache.zookeeper.KeeperException;
import org.junit.Test;

/**
 * @author huey China.
 * @Description : 模拟服务端 znode存储与修改
 * @Date Created in 2018/11/18 上午11:00
 */

public class ZookeeperConfigClient {

    /**
     * 模拟某个节点存储机制
     */
    private String path = "/config_node";
    private String pathValue = null;
    private ZookeeperConfigClientHandler zookeeperConfigClientHandler = null;


    /**
     * @author huey China.
     * @Description : 启动客户端,监听服务端
     * @Date Created in 2018/11/18 上午11:34
     */
    @Test
    public void testStart() throws InterruptedException {
        zookeeperConfigClientHandler = new ZookeeperConfigClientHandler();
        Thread.sleep(Integer.MAX_VALUE);
    }

    /**
     * @author huey China.
     * @Description : 客户端获取数据
     * @Date Created in 2018/11/18 上午11:34
     */
    @Test
    public void testGetData() throws KeeperException, InterruptedException {
        System.out.println("zkconfig new value is " + zookeeperConfigClientHandler.getData(this.path, true));
        System.out.println("内存 value is " + zookeeperConfigClientHandler.getNodes().get(this.path));
    }
}

核心代码

image.png

服务端与客户端启动前

image.png

启动后

image.png

服务端运行testUpdate后,客户端收到监听,并更新最新配置数据(其他UT类似)

image.png

总结

利用了zk的监听原理,底层是netty(juc+nio+序列化),使用上还是比较简单的,其他场景待续!

.参考

官网:http://zookeeper.apache.org
书籍:从Paxos到Zookeeper
网课: 推荐 慕课网 图灵学院 谷粒学院

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容