zookeeper入门到实战

一.zookeeper介绍

ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现。分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅负载均衡命名服务分布式协调/通知集群管理Master 选举配置维护名字服务分布式同步分布式锁和分布式队列等功能。

数据模型ZooKeeper 允许分布式进程通过共享的层次结构命名空间进行相互协调,这与标准文件系统类似。名称空间由 ZooKeeper 中的数据寄存器组成,称为 Znode,这些类似于文件和目录。与典型文件系统不同,ZooKeeper 数据保存在内存中,这意味着 ZooKeeper 可以实现高吞吐量和低延迟

顺序访问:对于来自客户端的每个更新请求,ZooKeeper 都会分配一个全局唯一的递增编号。这个编号反应了所有事务操作的先后顺序,应用程序可以使用 ZooKeeper 这个特性来实现更高层次的同步原语。这个编号也叫做时间戳zxidZooKeeper Transaction Id)。

可构建集群:为了保证高可用,最好是以集群形态来部署 ZooKeeper,这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么 ZooKeeper 本身仍然是可用的。客户端在使用 ZooKeeper 时,需要知道集群机器列表,通过与集群中的某一台机器建立 TCP 连接来使用服务。客户端使用这个 TCP 链接来发送请求、获取结果、获取监听事件以及发送心跳包。如果这个连接异常断开了,客户端可以连接到另外的机器上。

  • 上图中每一个 Server 代表一个安装 ZooKeeper 服务的服务器。组成 ZooKeeper服务的服务器都会在内存中维护当前的服务器状态,并且每台服务器之间都互相保持着通信。集群间通过 Zab 协议(Zookeeper Atomic Broadcast)来保持数据的一致性。
  • Zookeeper服务器有三种角色:LeaderFollowerObserver,集群中的所有机器通过一个 Leader 选举过程来选定一台称为 “Leader” 的机器。Leader 既可以为客户端提供写服务又能提供读服务。除了 Leader 外,FollowerObserver只能提供读服务FollowerObserver 唯一的区别在于Observer 机器不参与 Leader 的选举过程,也不参与写操作的“过半写成功”策略,因此 Observer 机器可以在不影响写性能的情况下提升集群的读性能。
  • ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性

工作原理

  1. Zookeeper的核心是原子广播,这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议
  2. Zab协议有两种模式,它们分别是恢复模式广播模式。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数server的完成了和leader状态同步以后,恢复模式就结束了。状态同步保证了leaderserver具有相同的系统状态。一旦leader已经和多数的follower进行了状态同步后,他就可以开始广播消息了,即进入广播状态。这时候当一个server加入zookeeper服务中,它会在恢复模式下启动,发现leader,并和leader进行状态同步。待到同步结束,它也参与消息广播。
  3. Zookeeper服务一直维持在Broadcast状态,直到leader崩溃了或者leader失去了大部分的followers支持

Leader选举

  1. 广播模式需要保证proposal提议)被按顺序处理leader来执行写操作),因此zk采用了递增的事务id号(zxid)来保证。所有的提议都在被提出的时候加上了zxid。实现中zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch。低32位是个递增计数。
  2. leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的server恢复到一个正确的状态。每个Server启动以后都询问其它的Server它要投票给谁。对于其他server的询问,server每次根据自己的状态都回复自己推荐的leaderid和上一次处理事务的zxid(系统启动时每个server都会推荐自己),收到所有Server回复以后,就计算出zxid最大的哪个Server,并将这个Server相关信息设置成下一次要投票的Server。计算这过程中获得票数最多的的sever为获胜者,如果获胜者的票数超过半数,则改server被选为leader。否则,继续这个过程,直到leader被选举出来

二.使用Zookeeper

 1        //客户端连接zookeeper服务器
 2         ZooKeeper zkClient = new ZooKeeper(CONNECT_STR, 50000, new Watcher() {
 3             @Override
 4             public void process(WatchedEvent watchedEvent) {
 5                 //监控服务节点变化
 6                 System.out.println("sssss");
 7             }
 8         });
 9
10         //获取根节点下的所有节点
11         List<String> nodeList= zkClient.getChildren("/",null);
12
13         System.out.println(nodeList.toString());
14
15         //Stat isExists= zkClient.exists(LOCK_ROOT_PATH,null);
16         //在test父节点下创建子节点
17         String lockPath = zkClient.create("/test/why","why".getBytes(),
18         ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);

代码中需要注意的是如果父节点不存在,会报异常,同时父节点不能是临时节点。

Znode

  1. ZooKeeper中,“节点"分为两类,第一类同样是指构成集群的机器,我们称之为机器节点,第二类则是指数据模型中的数据单元,我们称之为数据节点一ZNode。
  2. ZooKeeper 将所有数据存储在内存中,数据模型是一棵树(Znode Tree),由斜杠(/)的进行分割的路径,就是一个
    Znode,例如/foo/path1。每个上都会保存自己的数据内容,同时还会保存一系列属性信息。
  3. zookeeper有四类节点:PERSISTENT(持久的)EPHEMERAL(暂时的)PERSISTENT_SEQUENTIAL(持久化顺序编号目录节点)EPHEMERAL_SEQUENTIAL(暂时化顺序编号目录节点)

Session

  1. Session 指的是 ZooKeeper 服务器与客户端会话。在 ZooKeeper 中,一个客户端连接是指客户端和服务器之间的一个 TCP 长连接
  2. 客户端启动的时候,首先会与服务器建立一个 TCP连接,从第一次连接建立开始客户端会话的生命周期也开始了。通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向Zookeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的 Watch 事件通知
  3. SessionsessionTimeout值用来设置一个客户端会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在sessionTimeout规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。在为客户端创建会话之前,服务端首先会为每个客户端都分配一个sessionID。由于 sessionIDZookeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于这个sessionID 的。因此,无论是哪台服务器为客户端分配的 sessionID,都务必保证全局唯一

Watcher:是 ZooKeeper 中的一个很重要的特性。ZooKeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性。

Version: Zookeeper 的每个 ZNode 上都会存储数据,对应于每个 ZNodeZookeeper 都会为其维护一个叫作 Stat 的数据结构。Stat 中记录了这个 ZNode 的三个数据版本,分别是:version(当前节点版本)、cversion当前节点的子节点版本)、aversion当前节点的ACL版本

ACLZooKeeper 采用 ACLAccessControlLists)策略来进行权限控制,类似于 UNIX 文件系统的权限控制。ZooKeeper 定义了 5 种权限:CREATE/READ/WRITE/DELETE/ADMIN


三.通过zookeeper实现分布式锁

      package com.why;

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

      import java.io.IOException;
      import java.util.Collections;
      import java.util.List;

     /*
     *  分布式锁
     * */
     public class DistributeLock {

         private static final String LOCK_ROOT_PATH = "/test";
         //private static final String LOCK_NODE_NAME = "Lock";

         private static ZooKeeper _zkClient;

         static {
             try {
                 _zkClient = new ZooKeeper("192.168.6.132:2181", 500000, null);
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }

         public static String getLock() {
             try {

                 //System.out.println(_zkClient.getChildren("/",false));

                 String lockPath = _zkClient.create( "/test/why", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
                 //System.out.println(lockPath);
                 //System.out.println(_zkClient.getChildren(LOCK_ROOT_PATH,false));
                 if (tryLock(lockPath))
                     return lockPath;
                 else
                     return null;
             } catch (Exception ex) {
                 ex.printStackTrace();
                 return null;
             }
         }

         private static boolean tryLock(String lockPath) throws KeeperException, InterruptedException {
             List<String> lockPaths = _zkClient.getChildren(LOCK_ROOT_PATH, false);
             Collections.sort(lockPaths);
             int index=lockPaths.indexOf(lockPath.substring(LOCK_ROOT_PATH.length()+1));
             if(index==0){
                 //获得锁
                 return true;
             }
             else{
                 String preLockPath="/"+lockPaths.get(index-1);

                 Watcher watcher=new Watcher() {
                     @Override
                     public void process(WatchedEvent watchedEvent) {
                         synchronized (this){
                             //唤醒线程
                             notifyAll();
                         }
                     }
                 };

                 Stat stat=_zkClient.exists(preLockPath,watcher);

                 if(stat==null){
                     return tryLock(lockPath);
                 }else{
                     synchronized (watcher){
                         watcher.wait();
                     }
                     return tryLock(lockPath);
                 }

             }

         }

         public static void closeZkClient() throws InterruptedException {
             _zkClient.close();
         }

         public static void releaseLock(String lockPath) throws KeeperException, InterruptedException {
             _zkClient.delete(lockPath,-1);
         }
     }

测试:

    package com.why;

    import org.apache.zookeeper.KeeperException;
    import org.apache.zookeeper.ZooKeeper;

    import java.io.IOException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public class MultiThreadDemo {

        private static  int counter = 0;

        public  static  void plus() throws InterruptedException {
            Thread.sleep(500);
            counter++;
            //System.out.println(counter);
        }

        public static int Count(){
            return counter;
        }

        public static void main(String[] args) throws IOException, KeeperException, InterruptedException {

            ExecutorService executor= Executors.newCachedThreadPool();
            final int num=10;
            for(int i=0;i<num;i++){
                executor.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            String path = DistributeLock.getLock();
                            System.out.println(path);
                            plus();
                            DistributeLock.releaseLock(path);
                            System.out.println(Count());
                        } catch (InterruptedException | KeeperException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
            executor.shutdown();

        }
    }


zookeeper入门到实战

原文地址:https://blog.51cto.com/14230003/2374617

时间: 2024-10-07 22:37:12

zookeeper入门到实战的相关文章

Extjs5.0从入门到实战开发信息管理系统(Extjs基础、Extjs5新特性、Spring、Spring mvc、Mybatis)视频教程

Extjs5.0从入门到实战开发信息管理系统(Extjs基础.Extjs5新特性.Spring.Spring mvc.Mybatis)视频教程下载   联系QQ:1026270010 Extjs作为一款优秀的JS前端开发框架以其良好的架构.丰富的UI组件库.完善的文档和社区支持等诸多优点拥有广泛的市场应用空间,开发人员无需过多的关注HTML.CSS甚至各种常用JS算法,只需把精力放在业务逻辑上,利用各种组件的相互组合调用便可轻松而高效的开发出系统的前端页面. Extjs5在之前版本的基础上又推出

《Docker技术入门与实战》pdf

下载地址:网盘下载 内容简介  · · · · · · [编辑推荐] <Docker技术入门与实战>是中国首部docker著作,一线Docker先驱实战经验结晶,来自IBM和新浪等多位技术专家联袂推荐! <Docker技术入门与实战>结合企业生产环境,深入浅出地剖析 Docker 的核心概念.应用技巧.实现原理以及生态环境,为解决各类问题提供了有价值的参考. [内容简介] 在云计算时代,开发者将应用转移到云上已经解决了硬件管理的问题,然而软件配置和管理相关的问题依然存在.Docke

CMake快速入门教程-实战

http://www.ibm.com/developerworks/cn/linux/l-cn-cmake/ http://blog.csdn.net/dbzhang800/article/details/6314073 http://www.cnblogs.com/coderfenghc/archive/2013/01/20/2846621.html http://blog.sina.com.cn/s/blog_4aa4593d0100q3bt.html http://hahack.com/c

docker-9 supervisord 参考docker从入门到实战

参考docker从入门到实战 使用 Supervisor 来管理进程 Docker 容器在启动的时候开启单个进程,比如,一个 ssh 或者 apache 的 daemon 服务.但我们经常需要在一个机器上开启多个服务,这可以有很多方法,最简单的就是把多个启动命令放到一个启动脚本里面,启动的时候直接启动这个脚本,另外就是安装进程管理工具. 本小节将使用进程管理工具 supervisor 来管理容器中的多个进程.使用 Supervisor 可以更好的控制.管理.重启我们希望运行的进程.在这里我们演示

从入门到实战,Netty多线程篇案例集锦

从入门到实战,Netty多线程篇案例集锦 原创 2015-09-10 李林峰 InfoQ Netty案例集锦系列文章介绍 1|Netty的特点 Netty入门比较简单,主要原因有如下几点: Netty的API封装比较简单,将复杂的网络通信通过BootStrap等工具类做了二次封装,用户使用起来比较简单: Netty源码自带的Demo比较多,通过Demo可以很快入门: Netty社区资料.相关学习书籍也比较多,学习资料比较丰富. 但是很多入门之后的Netty学习者遇到了很多困惑,例如不知道在实际项

Docker入门与实战系列:热点问题

Docker入门与实战--<Docker ABC>电子书 https://github.com/gudaoxuri/Docker_ABC 11. 热点问题 11.1. 容器如何使用静态IP 默认情况下Docker容器的IP是动态分配的,要使用静态IP时我们会思考一下: 为什么需要静态IP?如果是为了两个容器间通信可以 使用--link 指定-h来指定hostname并指定-dns到宿主机 让容器开放上层服务 如果这样都满足不了您的要求那么可以参考 http://huataihuang.gith

赞一个 kindle电子书有最新的计算机图书可买了【Docker技术入门与实战】

最近对docker这个比较感兴趣,找一个比较完整的书籍看看,在z.cn上找到了电子书,jd dangdang看来要加油啊 Docker技术入门与实战 [Kindle电子书] ~ 杨保华 戴王剑 曹亚仑 (作者) http://www.amazon.cn/Docker技术入门与实战-杨保华-戴王剑-曹亚仑/dp/B00SMJ0VFA/ref=sr_1_2?s=digital-text&ie=UTF8&qid=1435217727&sr=1-2&keywords=docker

Extjs视频教程_Extjs5.0从入门到实战开发信息管理系统

Extjs5.0从入门到实战开发信息管理系统(Extjs基础.Extjs5新特性.Spring.Spring mvc.Mybatis)适合人群:初级课时数量:40课时用到技术:Extjs基础,Extjs5新特性,sencha cmd,spring,spring mvc, mybatis涉及项目:信息管理系统核心框架(mvvm+mvc架构)咨询qq:1840215592课程内容简介:1.课程研发环境开发工具:eclipse,sencha cmd:数据库工具:mysql5,mysql workben

xgboost入门与实战(原理篇)

http://blog.csdn.net/sb19931201/article/details/52557382 xgboost入门与实战(原理篇) 前言: xgboost是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包,比常见的工具包快10倍以上.在数据科学方面,有大量kaggle选手选用它进行数据挖掘比赛,其中包括两个以上kaggle比赛的夺冠方案.在工业界规模方面,xgboost的分布式版本有广泛的可移植性,支持在YARN, MPI, Sun