zoukankan      html  css  js  c++  java
  • 分布式之Zookeeper一(分布式锁与Zookeeper集群)

      说到分布式开发,不得不说的就是zookeeper了;zookeeper官网说到Apache ZooKeeper致力于开发和维护可实现高度可靠的分布式协调的开源服务器那么zk作为一个协调者的存在,是分布式比不可少的一部分。废话不多说,直接上干货

      Zookeeper(https://zookeeper.apache.org/)的安装包可以直接在官网上获取,https://zookeeper.apache.org/doc/current/zookeeperStarted.html这里有Zookeeper的一些常用的简单命令,我们可以尝试着去试试它。

      下面来说分布式锁,它用到的场景;比如:我们常说的惊群效应、Zookeeper集群争先读取缓存等。这里可能有人提到用redis实现的分布式锁,其实对比redis和Zookeeper的官网叙述,我们就能清晰的发现:Zookeeper比Redis更适合去做分布式锁。Zookeeper的担保第一条就是它的顺序性和一致性,其次是它的原子性。大家也可以详细的去了解一下。再分清楚这些之后,我们可以试着思考下Zookeeper它是怎么去实现的分布式锁?根据什么去实现的?

      可以想到如何获取到Zookeeper的每个节点以及子节点变化,Zookeeper的Watch机制充分的实现了这一点。通过Watch机制可以清晰的监听到Zookeeper的每个节点的变化。自然而然的这里也要用到Zookeeper的第三方客户端。Zookeeper的第三方客户端有两个;一个是zkclient、一个是curator。在curator中它自己已经实现了分布式锁,感兴趣的可以去看看它的实现源码。

      在第三方客户端连接到Zookeeper之后,就可以开始实现分布式锁了。锁的排他性、堵塞性、可重入性。排他性zk默认就实现了,zk的节点必须是唯一的。分布式锁采用Zookeeper的临时顺序节点来实现,首先获取锁,创建一个Zookeeper的临时顺序节点;然后需要一个栅栏(CountDownLatch),确保所有人都拿到自己的编号,即在同一起跑线上。然后开始抢锁,给一个发令枪(CountDown)。然后抢到锁的就去执行自己的业务,watch再次监听节点数据变化,然后请求线程去进行阻塞等待,接下来再删除节点,释放锁。

     1 public boolean tryLock() {
     2         
     3         if(currentPath.get() == null || !client.exists(currentPath.get())) {
     4             String node = client.createEphemeralSequential(LockPath+"/", "locked");
     5             currentPath.set(node);
     6         }
     7         
     8         
     9         List<String> children =client.getChildren(LockPath);
    10         // 排序list
    11         Collections.sort(children);
    12         
    13         // 判断当前节点是否是最小的
    14         if(currentPath.get().equals(LockPath+"/"+children.get(0))) {
    15             return true;
    16         }else {
    17             
    18             int curIndex = children.indexOf(currentPath.get().substring(LockPath.length() + 1));
    19             String bnode = LockPath+"/"+children.get(curIndex -1);
    20             beforePath.set(bnode);
    21         }
    22         return false;
    23     }
    24 
    25 
    26     public void lock() {
    27         if(! tryLock()) {
    28             // 阻塞等待锁的释放
    29             waitForLock();
    30             // 重新抢锁
    31             lock();
    32         }
    33     }
    34     private void waitForLock() {
    35         
    36         CountDownLatch cdl = new CountDownLatch(1);
    37         // 用zkwatcher事件来通知
    38             IZkDataListener listener = new IZkDataListener() {
    39 
    40             public void handleDataDeleted(String dataPath) throws Exception {
    41                 System.out.println("================zk节点被删除================");
    42                 cdl.countDown();
    43             }
    44 
    45             public void handleDataChange(String dataPath, Object data) throws Exception {
    46             }
    47         };
    48         // watcher /zk 数据变化
    49         client.subscribeDataChanges(beforePath.get(), listener);
    50         
    51         // 请求线程去进行阻塞等待
    52         if(client.exists(beforePath.get())) {
    53             try {
    54                 cdl.await();
    55             } catch (InterruptedException e) {
    56                 e.printStackTrace();
    57             }
    58         }
    59         // 取消注册事件
    60         client.unsubscribeDataChanges(beforePath.get(), listener);
    61     }

    至此一个分布式锁就实现了。

      接下来说Zookeeper的伪集群。搭建的时候需要注意的情况:
    1、DataDir的位置。
    2、Zookeeper的端口号
    3、


    4、myid文件,myid文件是创建在DataDir目录下的,myid文件就是给一个id数,id数需与server.1 ... 后边的编号一致。
    然后分别启动三台服务器,注意看服务器输出的日志消息。不出意外的话Zookeeper的集群就可以搭建成功了!
    
    
  • 相关阅读:
    js中 var let const 区别
    img标签src引用网络图片,响应403的解决方法
    统计开发push数据
    gp日志查看
    node之path模块
    算法相关问题
    常用的 curl 发送 http 请求 命令
    Python与Go列表切片越界的对比
    golang时间与时区相关操作总结
    go语言结构体转map的方法
  • 原文地址:https://www.cnblogs.com/zhanvo/p/11589235.html
Copyright © 2011-2022 走看看