zoukankan      html  css  js  c++  java
  • 分布式设计与开发(三)------高一致性服务ZooKeeper

    http://blog.csdn.net/cutesource/article/details/5822459


    ZooKeeper的实现机理

    ZooKeeper的实现机理是我看过的开源框架中最复杂的,它的解决是分布式环境中的一致性问题,这个场景也决定了其实现的复杂性。看了两三天的源码还是有些摸不着头脑,有些超出了我的能力,不过通过看文档和其他高人写的文章大致清楚它的原理和基本结构。

    1)ZooKeeper的基本原理

    ZooKeeper是以Fast Paxos算法为基础的,在前一篇 blog 中大致介绍了一下paxos,而没有提到的是paxos存在活锁的问题,也就是当有多个 proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,而Fast Paxos作了一些优化,通过选举产生一个leader,只有leader才能提交propose,具体算法可见Fast Paxos 。因此,要想弄得ZooKeeper首先得对Fast Paxos有所了解。

    2)ZooKeeper的基本运转流程

    ZooKeeper主要存在以下两个流程:

     

    • ZooKeeper主要存在以下两个流程:

      • 选举Leader
      • 同步数据

      选举Leader过程中算法有很多,但要达到的选举标准是一致的:

      • Leader要具有最高的zxid 
      • 集群中大多数的机器得到响应并follow选出的Leader

      同步数据这个流程是ZooKeeper的精髓所在,并且就是Fast Paxos算法的具体实现。一个牛人画了一个ZooKeeper数据流动图,比较直观地描述了ZooKeeper是如何同步数据的。 

     

    以上两个核心流程我暂时还不能悟透其中的精髓,这也和我还没有完全理解Fast Paxos算法有关,有待后续深入学习

    ZooKeeper的应用领域

    Tim在blog中提到了Paxos所能应用的几个主要场景,包括database replication、naming service、config配置管理、access control list等等,这也是ZooKeeper可以应用的几个主要场景。此外, ZooKeeper官方文档中提到了几个更为基础的分布式应用,这也算是ZooKeeper的妙用吧

    1)分布式Barrier

    Barrier是一种控制和协调多个任务触发次序的机制,简单说来就是搞个闸门把欲执行的任务给拦住,等所有任务都处于可以执行的状态时,才放开闸门。它的机理可以见下图所示:

    在单机上JDK提供了CyclicBarrier这个类来实现这个机制,但在分布式环境中JDK就无能为力了。在分布式里实现Barrer需要高一致性做保障,因此 ZooKeeper可以派上用场,所采取的方案就是用一个Node作为Barrer的实体,需要被Barrer的任务通过调用exists()检测这个Node的存在,当需要打开Barrier的时候,删掉这个Node,ZooKeeper的watch机制会通知到各个任务可以开始执行。

    2) 分布式 Queue

    与 Barrier类似 分布式环境中 实现Queue也需要高一致性做保障, ZooKeeper提供了一个种简单的方式,ZooKeeper通过一个Node来维护Queue的实体,用其children来存储Queue的内容,并且 ZooKeeper的create方法中提供了顺序递增的模式,会自动地在name后面加上一个递增的数字来插入新元素。可以用其 children来构建一个queue的数据结构,offer的时候使用create,take的时候按照children的顺序删除第一个即可。 ZooKeeper保障了各个server上数据是一致的,因此也就实现了一个 分布式 Queue。take和offer的实例代码如下所示:

     

    [java] view plaincopy
     
    1. /** 
    2.  * Removes the head of the queue and returns it, blocks until it succeeds. 
    3.  * @return The former head of the queue 
    4.  * @throws NoSuchElementException 
    5.  * @throws KeeperException 
    6.  * @throws InterruptedException 
    7.  */  
    8. public byte[] take() throws KeeperException, InterruptedException {  
    9.     TreeMap<Long,String> orderedChildren;  
    10.     // Same as for element.  Should refactor this.  
    11.     while(true){  
    12.         LatchChildWatcher childWatcher = new LatchChildWatcher();  
    13.         try{  
    14.             orderedChildren = orderedChildren(childWatcher);  
    15.         }catch(KeeperException.NoNodeException e){  
    16.             zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);  
    17.             continue;  
    18.         }  
    19.         if(orderedChildren.size() == 0){  
    20.             childWatcher.await();  
    21.             continue;  
    22.         }  
    23.         for(String headNode : orderedChildren.values()){  
    24.             String path = dir +"/"+headNode;  
    25.             try{  
    26.                 byte[] data = zookeeper.getData(path, falsenull);  
    27.                 zookeeper.delete(path, -1);  
    28.                 return data;  
    29.             }catch(KeeperException.NoNodeException e){  
    30.                 // Another client deleted the node first.  
    31.             }  
    32.         }  
    33.     }  
    34. }  
    35. /** 
    36.  * Inserts data into queue. 
    37.  * @param data 
    38.  * @return true if data was successfully added 
    39.  */  
    40. public boolean offer(byte[] data) throws KeeperException, InterruptedException{  
    41.     for(;;){  
    42.         try{  
    43.             zookeeper.create(dir+"/"+prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);  
    44.             return true;  
    45.         }catch(KeeperException.NoNodeException e){  
    46.             zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);  
    47.         }  
    48.     }  
    49. }  

    3)分布式lock

    利用 ZooKeeper实现 分布式lock,主要是通过一个Node来代表一个Lock,当一个client去拿锁的时候,会在这个Node下创建一个自增序列的child,然后通过getChildren()方式来check创建的child是不是最靠前的,如果是则拿到锁,否则就调用exist()来check第二靠前的child,并加上watch来监视。当拿到锁的child执行完后归还锁,归还锁仅仅需要删除自己创建的child,这时watch机制会通知到所有没有拿到锁的client,这些child就会根据前面所讲的拿锁规则来竞争锁。

  • 相关阅读:
    vue中mixins的使用方法和注意点(详)
    深入理解.sync修饰符
    less语法详解
    vue中的history和hash
    在Vue组件中获取全局的点击事件
    echarts
    【SQL Server性能优化】运用SQL Server的全文检索来提高模糊匹配的效率
    【SQL Server备份恢复】维护计划实现备份:每周数据库完整备份、每天差异备份、每小时日志备份
    通过SQL Server的扩展事件来跟踪SQL语句在运行时,时间都消耗到哪儿了?
    如何向视图插入数据
  • 原文地址:https://www.cnblogs.com/leeeee/p/7276162.html
Copyright © 2011-2022 走看看