zookeeper 官網地址:http://zookeeper.apache.org/java
zookeeper 數據模型node
zookeeper 表現爲一個分層的文件系統目錄樹結構(不一樣於文件系統的是,節點能夠有本身的數據,而文件系統中的目錄節點只有子節點)apache
每一個節點均可以有關聯的數據和子節點 緩存
ZooKeeper樹中的節點稱做znode。znode會維護一個包含數據修改和ACL修改版本號的Stat結構體,這個結構體還包含時間戳字段。版本號和時間戳讓ZooKeeper能夠校驗緩存,協調更新。每次修改znode數據的時候,版本號會增長。客戶端獲取數據的同時,也會取得數據的版本號。執行更新或者刪除操做時,客戶端必須提供版本號。若是提供的版本號與數據的實際版本不匹配,則更新操做失敗。session
版本號有三種:version(znode數據修改的次數)、cversion(znode子節點修改的次數),以及aversion(znode的ACL修改次數)。分佈式
主節點是臨時節點 EPHEMERAL、EPHEMERAL_SEQUENTIAL 不能構建子節點ide
Zookeeper 中最有特點且最不容易理解的是監視(Watches)。Zookeeper 全部的讀操做——getData(), getChildren(), 和 exists() 都 能夠設置監視(watch),監視事件能夠理解爲一次性的觸發器this
3.spa
判斷當前客戶端 LockID 是否爲最小 ,最小就得到鎖 執行定時任務code
public class ZKClient implements Watcher { private String hosts; private String ownerPath; private long lockID; public long getLockID() { return lockID; } private ZooKeeper zookeeper = null; private static final String rootNode="/hnm"; public ZooKeeper getZookeeper() { return zookeeper; } public void setZookeeper(ZooKeeper zookeeper) { this.zookeeper = zookeeper; } private static final int sessionTimeOut = 30000;//30s會話延時 private CountDownLatch connectSemaphore = new CountDownLatch(1);//同步計數器 public String getHosts() { return hosts; } public void setHosts(String hosts) { this.hosts = hosts; } public void initZookeeper(){ try { this.zookeeper = new ZooKeeper(hosts, sessionTimeOut, this); connectSemaphore.await(); Stat rootstat = zookeeper.exists(rootNode,false); if(rootstat == null){ zookeeper.create(rootNode, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } if(this.ownerPath ==null || zookeeper.exists(this.ownerPath,false) == null){ this.ownerPath = zookeeper.create(rootNode+"/lock-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); }else{ zookeeper.delete(this.ownerPath, -1); } this.lockID = Long.parseLong(this.ownerPath.substring(this.ownerPath.lastIndexOf("-")+1)); } catch (Exception e) { e.printStackTrace(); } } public String getOwnerPath() { return ownerPath; } @Override public void process(WatchedEvent event) { KeeperState state = event.getState(); if(KeeperState.SyncConnected == state){ connectSemaphore.countDown(); }else if(KeeperState.Expired == state || KeeperState.Disconnected == state){ this.initZookeeper(); } } }
/** * 分佈式鎖 * @author Administrator * */ public class DistributeLock { private static final Logger LOG = Logger.getLogger(DistributeLock.class); private ZKClient zkclient; public void setZkclient(ZKClient zkclient) { this.zkclient = zkclient; } private static final String rootNode = "/hnm"; /** * 是否獲得分佈式鎖 * 判斷當前zookeeper客戶端session 是不是最小的 若是是 就表示拿到分佈式鎖 * @return */ public boolean isGetLock(){ ZooKeeper client =zkclient.getZookeeper(); boolean flag=true; try { System.out.println(zkclient.getOwnerPath()); List<String> list = client.getChildren(rootNode, false); long ownerID = zkclient.getLockID(); for(String str:list){ System.out.println(str); long id = Long.parseLong(str.substring(str.lastIndexOf("-")+1)); if(id < ownerID){ flag= false; break; } System.out.println(id); } } catch (Exception e) { LOG.error(e); } return flag; } }
4.有可能出現的問題
定時任務間隔時間過短: 某一個客戶端斷開連接 但定時任務正在執行 。另外一個客戶端發現lockid變成最小的,也但是執行