使用zookeeper实现静态数据中心化配置管理

来源:互联网 发布:python全栈 编辑:程序博客网 时间:2024/06/02 12:03
各个项目都会存在静态数据配置,这些数据平台变化很少,为提高性能一般采用缓存的方式缓存数据。如果采用分布式缓存,网络成本比较高不太适合 
一般采用本地缓存,在单机环境下修改缓存数据方式比较简单,更新数据库的同时,也修改更新本地缓存,但在集群模式下可就没有这么简单,最简单直接 
的方式就是一台台服务器等去修改,费时费力。或者通过jms消息同步的方式进行处理,具体不描述太多。这里介绍另外一种方式,即使用zookeeper实现 
静态数据中心化配置管理。 
    先简单介绍一下zookeeper,ZooKeeper是近期比较热门的一个Paxos算法实现,也是Hadoop下的一个子项目,被认为是Google Chubby的开源版, 
主要用来在分布式环境下提供分布式锁、配置管理、名字服务、群组服务。它具有很高的可用性、稳定性、可靠性。它在分布式应用中像一把瑞士军刀, 
很多地方都用得着。 
为了缓存数据,需要一个HashMap对象,但JDK中的HashMap是不支持分布式环境同步数据的。为此需要结合zookeeper重新实现一个HashMap, 
取名叫做ZKHashMap。连接到zookeeper服务器的任何一个客户端修改了ZKHashMap。能够通过zookeeper服务器主动同步到其它连接到zookeeper服务器的客户端。 
搜索发现已经有这样的实现工具包:menagerie(https://github.com/openUtility/menagerie)。官网描述为:Menagerie is an implementation of the 
Java Concurrency Libraries based on the popular Apache ZooKeeper。主要功能有分布式集合、分布式队列、分布式锁的实现。有兴趣可以去学习一下源码 
为了演示其效果,做个测试,代码如下, 

Java代码  收藏代码
  1. public class TestZKHashMap {  
  2.     private static final String hostString = "localhost:2181";  
  3.     private static final String baseHashMapPath = "/test-maps";  
  4.     private static final String baseLockPath = "/test-locks";  
  5.     private static final String Init_Done = "/initData";  
  6.     private static final int timeout = 2000;  
  7.   
  8.     private static ZooKeeper zk1, zk2;  
  9.     private static ZkSessionManager zkSessionManager1, zkSessionManager2;  
  10.     private static ZkHashMap<String,Person> testMap1, testMap2;  
  11.     private static Serializer<Entry<String, Person>> serializer = new JavaSerializer<String, Person>();  
  12.       
  13.     public static void main(String[] args) throws Exception {  
  14.         setup();  
  15.         final CountDownLatch latch = new CountDownLatch(2);  
  16.           
  17.         Thread thread1 = new Thread() {  
  18.             @Override  
  19.             public void run() {  
  20.                 initData(zk1, zkSessionManager1);  
  21.                 String znode = "test1";  
  22.                 Person person = new Person("melin");   
  23.                 testMap1.put(znode, person);  
  24.                 latch.countDown();  
  25.             }  
  26.         };  
  27.   
  28.         Thread thread2 = new Thread() {  
  29.             @Override  
  30.             public void run() {  
  31.                 initData(zk2, zkSessionManager2);  
  32.                 String znode = "test2";  
  33.                 Person person = new Person("melin");   
  34.                 testMap2.put(znode, person);  
  35.                 latch.countDown();  
  36.             }  
  37.         };  
  38.         thread1.start();  
  39.         thread2.start();  
  40.         latch.await();  
  41.         Thread.sleep(100);  
  42.   
  43.         if(testMap1.containsKey("test2")) {  
  44.             System.out.println("testMap1 包含 test2");  
  45.         }  
  46.           
  47.         if(testMap2.containsKey("test1")) {  
  48.             System.out.println("testMap2 包含 test1");  
  49.         }  
  50.           
  51.         tearDown();  
  52.     }  
  53.       
  54.     private static ZooKeeper newZooKeeper() throws IOException {  
  55.         return new ZooKeeper(hostString, timeout,new Watcher() {  
  56.             @Override  
  57.             public void process(WatchedEvent event) {  
  58.                 System.out.println("+++++++++"+event);  
  59.             }  
  60.         });  
  61.     }  
  62.       
  63.     public static void setup() throws Exception {  
  64.         zk1 = newZooKeeper();  
  65.         zk1.create(baseHashMapPath,new byte[]{}, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  66.         zkSessionManager1 = new BaseZkSessionManager(zk1);  
  67.         testMap1 = new ZkHashMap<String, Person>(baseHashMapPath, zkSessionManager1, serializer);  
  68.           
  69.         zk2 = newZooKeeper();  
  70.         zkSessionManager2 = new BaseZkSessionManager(zk2);  
  71.         testMap2 = new ZkHashMap<String, Person>(baseHashMapPath, zkSessionManager2, serializer);  
  72.     }  
  73.   
  74.     public static void tearDown() throws Exception{  
  75.         try{  
  76.             ZkUtils.recursiveSafeDelete(zk1,baseHashMapPath,-1);  
  77.             ZkUtils.recursiveSafeDelete(zk1,baseLockPath,-1);  
  78.             ZkUtils.recursiveSafeDelete(zk1,Init_Done,-1);  
  79.         }catch(KeeperException ke){  
  80.             //suppress because who cares what went wrong after our tests did their thing?  
  81.         }finally{  
  82.             zk1.close();  
  83.             zk2.close();  
  84.         }  
  85.     }  
  86.       
  87.     public static void initData(ZooKeeper zk, ZkSessionManager zkSessionManager) {  
  88.         final Lock lock = new ReentrantZkLock(baseLockPath, zkSessionManager);  
  89.         try {  
  90.             if (null == zk.exists(Init_Done, true)) {  
  91.                 // if the init_done node not exists we try to init  
  92.                 lock.lock();  
  93.                 if(zk.exists(Init_Done, true) != null) {  
  94.                     System.out.println("已经初始化数据"+zk);  
  95.                     return;  
  96.                 }  
  97.                 System.out.println("初始化数据"+zk);  
  98.                 //创建初始化成功标识,注意这个标志是永久节点  
  99.                 zk.create(Init_Done, null, Ids.OPEN_ACL_UNSAFE,  CreateMode.PERSISTENT);  
  100.                 //工作完成,释放锁  
  101.                 lock.unlock();  
  102.             } else {// if init_done exists we simply load data from gcih  
  103.                 System.out.println("已经初始化数据"+zk);  
  104.             }  
  105.         } catch (Exception e) {  
  106.             e.printStackTrace();  
  107.         }  
  108.     }  
  109. }  


感叹zookeeper用一个简单的树结构模型实现Paxos算法...... 

资料 
1:Paxos算法之旅(一)追本溯源 
http://rdc.taobao.com/team/jm/archives/397 
2:Paxos算法中文翻译 
   http://wenku.baidu.com/view/87276e1dfad6195f312ba6d7.html 
3:Blog:http://zoutm.iteye.com/blog/708324
0 0