zookeeper有watch事件,是一次性觸發的,當watch監視的數據發生變化時,通知設置了該watch的client,即watcher。
同樣,其watcher是監聽數據發送了某些變化,那就一定會有對應的事件類型和狀態類型。
事件類型:(znode節點相關的)
EventType.NodeCreated
EventType.NodeDataChanged
EventType.NodeChildrenChanged
EventType.NodeDeleted
狀態類型:(跟客戶端實例相關的)
keeperState.Disconnected
keeperState.SyncConnected
keeperState.AuthFailed
keeperState.Expired
watcher的特性:一次性、客戶端串行執行、輕量
一次性:對於ZK的watcher,只需要記住一點:zookeeper有watch事件,是一次性觸發的,當watch監視的數據發生變化時,通知設置了該watch的client,即watcher,由於zookeeper的監控都是一次性的,所以每次必須設置監控。
客戶端串行執行:客戶端Watcher回調的過程是一個串行同步的過程,這為我們保證了順序,同事需要開發人員注意一點,千萬不要因為一個Watcher的處理邏輯影響了整個客戶端的Watcher回調。
輕量:WatchedEvent 是Zookeeper整個Watcher通知機制的最小通知單元,整個結構只包含三部分:通知狀態、事件類型和節點路徑。也就是說Watcher通知非常的簡單,只會告訴客戶端發生了事件,而不會告知其具體內容,需要客戶端自己去進行獲取,比如NodeDataChanged事件,Zookeeper只會通知客戶端指定節點的數據發生了變更,而不會直接提供具體的數據內容。
1 package bjsxt.zookeeper.watcher; 2 3 import java.util.List; 4 import java.util.concurrent.CountDownLatch; 5 import java.util.concurrent.atomic.AtomicInteger; 6 7 import org.apache.zookeeper.CreateMode; 8 import org.apache.zookeeper.WatchedEvent; 9 import org.apache.zookeeper.Watcher; 10 import org.apache.zookeeper.Watcher.Event.EventType; 11 import org.apache.zookeeper.Watcher.Event.KeeperState; 12 import org.apache.zookeeper.ZooDefs.Ids; 13 import org.apache.zookeeper.ZooKeeper; 14 import org.apache.zookeeper.data.Stat; 15 16 /** 17 * Zookeeper Wathcher 18 * 本類就是一個Watcher類(實現了org.apache.zookeeper.Watcher類) 19 * @author(alienware) 20 * @since 2015-6-14 21 */ 22 public class ZooKeeperWatcher implements Watcher { 23 24 /** 定義原子變量 */ 25 AtomicInteger seq = new AtomicInteger(); 26 /** 定義session失效時間 */ 27 private static final int SESSION_TIMEOUT = 10000; 28 /** zookeeper服務器地址 */ 29 private static final String CONNECTION_ADDR = "192.168.80.88:2181"; 30 /** zk父路徑設置 */ 31 private static final String PARENT_PATH = "/testWatch"; 32 /** zk子路徑設置 */ 33 private static final String CHILDREN_PATH = "/testWatch/children"; 34 /** 進入標識 */ 35 private static final String LOG_PREFIX_OF_MAIN = "【Main】"; 36 /** zk變量 */ 37 private ZooKeeper zk = null; 38 /** 信號量設置,用於等待zookeeper連接建立之后 通知阻塞程序繼續向下執行 */ 39 private CountDownLatch connectedSemaphore = new CountDownLatch(1); 40 41 /** 42 * 創建ZK連接 43 * @param connectAddr ZK服務器地址列表 44 * @param sessionTimeout Session超時時間 45 */ 46 public void createConnection(String connectAddr, int sessionTimeout) { 47 this.releaseConnection(); 48 try { 49 zk = new ZooKeeper(connectAddr, sessionTimeout, this); 50 System.out.println(LOG_PREFIX_OF_MAIN + "開始連接ZK服務器"); 51 connectedSemaphore.await(); 52 } catch (Exception e) { 53 e.printStackTrace(); 54 } 55 } 56 57 /** 58 * 關閉ZK連接 59 */ 60 public void releaseConnection() { 61 if (this.zk != null) { 62 try { 63 this.zk.close(); 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 } 69 70 /** 71 * 創建節點 72 * @param path 節點路徑 73 * @param data 數據內容 74 * @return 75 */ 76 public boolean createPath(String path, String data) { 77 try { 78 //設置監控(由於zookeeper的監控都是一次性的所以 每次必須設置監控) 79 this.zk.exists(path, true); 80 System.out.println(LOG_PREFIX_OF_MAIN + "節點創建成功, Path: " + 81 this.zk.create( /**路徑*/ 82 path, 83 /**數據*/ 84 data.getBytes(), 85 /**所有可見*/ 86 Ids.OPEN_ACL_UNSAFE, 87 /**永久存儲*/ 88 CreateMode.PERSISTENT ) + 89 ", content: " + data); 90 } catch (Exception e) { 91 e.printStackTrace(); 92 return false; 93 } 94 return true; 95 } 96 97 /** 98 * 讀取指定節點數據內容 99 * @param path 節點路徑 100 * @return 101 */ 102 public String readData(String path, boolean needWatch) { 103 try { 104 return new String(this.zk.getData(path, needWatch, null)); 105 } catch (Exception e) { 106 e.printStackTrace(); 107 return ""; 108 } 109 } 110 111 /** 112 * 更新指定節點數據內容 113 * @param path 節點路徑 114 * @param data 數據內容 115 * @return 116 */ 117 public boolean writeData(String path, String data) { 118 try { 119 System.out.println(LOG_PREFIX_OF_MAIN + "更新數據成功,path:" + path + ", stat: " + 120 this.zk.setData(path, data.getBytes(), -1)); 121 } catch (Exception e) { 122 e.printStackTrace(); 123 } 124 return false; 125 } 126 127 /** 128 * 刪除指定節點 129 * 130 * @param path 131 * 節點path 132 */ 133 public void deleteNode(String path) { 134 try { 135 this.zk.delete(path, -1); 136 System.out.println(LOG_PREFIX_OF_MAIN + "刪除節點成功,path:" + path); 137 } catch (Exception e) { 138 e.printStackTrace(); 139 } 140 } 141 142 /** 143 * 判斷指定節點是否存在 144 * @param path 節點路徑 145 */ 146 public Stat exists(String path, boolean needWatch) { 147 try { 148 return this.zk.exists(path, needWatch); 149 } catch (Exception e) { 150 e.printStackTrace(); 151 return null; 152 } 153 } 154 155 /** 156 * 獲取子節點 157 * @param path 節點路徑 158 */ 159 private List<String> getChildren(String path, boolean needWatch) { 160 try { 161 return this.zk.getChildren(path, needWatch); 162 } catch (Exception e) { 163 e.printStackTrace(); 164 return null; 165 } 166 } 167 168 /** 169 * 刪除所有節點 170 */ 171 public void deleteAllTestPath() { 172 if(this.exists(CHILDREN_PATH, false) != null){ 173 this.deleteNode(CHILDREN_PATH); 174 } 175 if(this.exists(PARENT_PATH, false) != null){ 176 this.deleteNode(PARENT_PATH); 177 } 178 } 179 180 /** 181 * 收到來自Server的Watcher通知后的處理。 182 */ 183 @Override 184 public void process(WatchedEvent event) { 185 186 System.out.println("進入 process 。。。。。event = " + event); 187 188 try { 189 Thread.sleep(200); 190 } catch (InterruptedException e) { 191 e.printStackTrace(); 192 } 193 194 if (event == null) { 195 return; 196 } 197 198 // 連接狀態 199 KeeperState keeperState = event.getState(); 200 // 事件類型 201 EventType eventType = event.getType(); 202 // 受影響的path 203 String path = event.getPath(); 204 205 String logPrefix = "【Watcher-" + this.seq.incrementAndGet() + "】"; 206 207 System.out.println(logPrefix + "收到Watcher通知"); 208 System.out.println(logPrefix + "連接狀態:\t" + keeperState.toString()); 209 System.out.println(logPrefix + "事件類型:\t" + eventType.toString()); 210 211 if (KeeperState.SyncConnected == keeperState) { 212 // 成功連接上ZK服務器 213 if (EventType.None == eventType) { 214 System.out.println(logPrefix + "成功連接上ZK服務器"); 215 connectedSemaphore.countDown(); 216 } 217 //創建節點 218 else if (EventType.NodeCreated == eventType) { 219 System.out.println(logPrefix + "節點創建"); 220 try { 221 Thread.sleep(100); 222 } catch (InterruptedException e) { 223 e.printStackTrace(); 224 } 225 this.exists(path, true); 226 } 227 //更新節點 228 else if (EventType.NodeDataChanged == eventType) { 229 System.out.println(logPrefix + "節點數據更新"); 230 System.out.println("我看看走不走這里........"); 231 try { 232 Thread.sleep(100); 233 } catch (InterruptedException e) { 234 e.printStackTrace(); 235 } 236 System.out.println(logPrefix + "數據內容: " + this.readData(PARENT_PATH, true)); 237 } 238 //更新子節點 239 else if (EventType.NodeChildrenChanged == eventType) { 240 System.out.println(logPrefix + "子節點變更"); 241 try { 242 Thread.sleep(3000); 243 } catch (InterruptedException e) { 244 e.printStackTrace(); 245 } 246 System.out.println(logPrefix + "子節點列表:" + this.getChildren(PARENT_PATH, true)); 247 } 248 //刪除節點 249 else if (EventType.NodeDeleted == eventType) { 250 System.out.println(logPrefix + "節點 " + path + " 被刪除"); 251 } 252 else ; 253 } 254 else if (KeeperState.Disconnected == keeperState) { 255 System.out.println(logPrefix + "與ZK服務器斷開連接"); 256 } 257 else if (KeeperState.AuthFailed == keeperState) { 258 System.out.println(logPrefix + "權限檢查失敗"); 259 } 260 else if (KeeperState.Expired == keeperState) { 261 System.out.println(logPrefix + "會話失效"); 262 } 263 else ; 264 265 System.out.println("--------------------------------------------"); 266 267 } 268 269 /** 270 * <B>方法名稱:</B>測試zookeeper監控<BR> 271 * <B>概要說明:</B>主要測試watch功能<BR> 272 * @param args 273 * @throws Exception 274 */ 275 public static void main(String[] args) throws Exception { 276 277 //建立watcher 278 ZooKeeperWatcher zkWatch = new ZooKeeperWatcher(); 279 //創建連接 280 zkWatch.createConnection(CONNECTION_ADDR, SESSION_TIMEOUT); 281 //System.out.println(zkWatch.zk.toString()); 282 283 Thread.sleep(1000); 284 285 // 清理節點 286 zkWatch.deleteAllTestPath(); 287 288 if (zkWatch.createPath(PARENT_PATH, System.currentTimeMillis() + "")) { 289 290 Thread.sleep(1000); 291 292 293 // 讀取數據 294 System.out.println("---------------------- read parent ----------------------------"); 295 //zkWatch.readData(PARENT_PATH, true); 296 297 // 讀取子節點 298 System.out.println("---------------------- read children path ----------------------------"); 299 zkWatch.getChildren(PARENT_PATH, true); 300 301 // 更新數據 302 zkWatch.writeData(PARENT_PATH, System.currentTimeMillis() + ""); 303 304 Thread.sleep(1000); 305 306 // 創建子節點 307 zkWatch.createPath(CHILDREN_PATH, System.currentTimeMillis() + ""); 308 309 Thread.sleep(1000); 310 311 zkWatch.writeData(CHILDREN_PATH, System.currentTimeMillis() + ""); 312 } 313 314 Thread.sleep(50000); 315 // 清理節點 316 zkWatch.deleteAllTestPath(); 317 Thread.sleep(1000); 318 zkWatch.releaseConnection(); 319 } 320 321 }
zookeeper的ACL (AUTH)
ACL(Access Control List),Zookeeper作為一個分布式協調框架,其內部存儲的都是一些關乎分布式系統運行時狀態的元數據,尤其是涉及到一些分布式鎖、Master選舉和協調等應用場景。我們需要有效地保障Zookeeper中的數據安全,Zookeeper提供一套完善的ACL權限控制機制來保障數據的安全。
ZK提供了三種模式。權限模式,授權對象,權限。
權限模式:Scheme,開發人員最多使用一下四種權限模式:
IP:ip模式通過ip地址粒度來進行控制權限,例如配置了:ip:192.168.1.109即表示權限控制都是針對這個ip地址的,同時也支持按網段分配,比如192.168.1.*
Digest:digest是最常用的權限控制模式,也更符合我們對權限控制的認識,其類似於“username:password” 形式的權限標識進行權限配置,ZK會對形成的權限標識先后進行兩次編碼處理,分別是SHA-1加密算法、BASE64編碼。
World:World是一直最開放的全校性控制模式,這種模式可以看作為特殊的Digest,他僅僅是一個標識而已。
Super:超級用戶模式,在超級用戶模式下可以對ZK任意進行操作
權限對象:指的是權限賦予的用戶或者一個指定的實體,例如ip地址或機器等,在不同的模式下,授權對象是不同的,這種模式和權限對象一一對應。
權限:權限就是指那些通過權限檢測后可以被允許執行的操作,在ZK中,對數據的操作權限分為以下五大類:
CREATE,DELLETE,READ,WRITE,ADMIN
1 package bjsxt.zookeeper.auth; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.concurrent.CountDownLatch; 6 import java.util.concurrent.atomic.AtomicInteger; 7 8 import org.apache.zookeeper.CreateMode; 9 import org.apache.zookeeper.WatchedEvent; 10 import org.apache.zookeeper.Watcher; 11 import org.apache.zookeeper.Watcher.Event.EventType; 12 import org.apache.zookeeper.Watcher.Event.KeeperState; 13 import org.apache.zookeeper.ZooDefs.Ids; 14 import org.apache.zookeeper.ZooKeeper; 15 import org.apache.zookeeper.data.ACL; 16 import org.apache.zookeeper.data.Stat; 17 /** 18 * Zookeeper 節點授權 19 * @author(alienware) 20 * @since 2015-6-14 21 */ 22 public class ZookeeperAuth implements Watcher { 23 24 /** 連接地址 */ 25 final static String CONNECT_ADDR = "192.168.80.88:2181"; 26 /** 測試路徑 */ 27 final static String PATH = "/testAuth"; 28 final static String PATH_DEL = "/testAuth/delNode"; 29 /** 認證類型 */ 30 final static String authentication_type = "digest"; 31 /** 認證正確方法 */ 32 final static String correctAuthentication = "123456"; 33 /** 認證錯誤方法 */ 34 final static String badAuthentication = "654321"; 35 36 static ZooKeeper zk = null; 37 /** 計時器 */ 38 AtomicInteger seq = new AtomicInteger(); 39 /** 標識 */ 40 private static final String LOG_PREFIX_OF_MAIN = "【Main】"; 41 42 private CountDownLatch connectedSemaphore = new CountDownLatch(1); 43 44 @Override 45 public void process(WatchedEvent event) { 46 try { 47 Thread.sleep(200); 48 } catch (InterruptedException e) { 49 e.printStackTrace(); 50 } 51 if (event==null) { 52 return; 53 } 54 // 連接狀態 55 KeeperState keeperState = event.getState(); 56 // 事件類型 57 EventType eventType = event.getType(); 58 // 受影響的path 59 String path = event.getPath(); 60 61 String logPrefix = "【Watcher-" + this.seq.incrementAndGet() + "】"; 62 63 System.out.println(logPrefix + "收到Watcher通知"); 64 System.out.println(logPrefix + "連接狀態:\t" + keeperState.toString()); 65 System.out.println(logPrefix + "事件類型:\t" + eventType.toString()); 66 if (KeeperState.SyncConnected == keeperState) { 67 // 成功連接上ZK服務器 68 if (EventType.None == eventType) { 69 System.out.println(logPrefix + "成功連接上ZK服務器"); 70 connectedSemaphore.countDown(); 71 } 72 } else if (KeeperState.Disconnected == keeperState) { 73 System.out.println(logPrefix + "與ZK服務器斷開連接"); 74 } else if (KeeperState.AuthFailed == keeperState) { 75 System.out.println(logPrefix + "權限檢查失敗"); 76 } else if (KeeperState.Expired == keeperState) { 77 System.out.println(logPrefix + "會話失效"); 78 } 79 System.out.println("--------------------------------------------"); 80 } 81 /** 82 * 創建ZK連接 83 * 84 * @param connectString 85 * ZK服務器地址列表 86 * @param sessionTimeout 87 * Session超時時間 88 */ 89 public void createConnection(String connectString, int sessionTimeout) { 90 this.releaseConnection(); 91 try { 92 zk = new ZooKeeper(connectString, sessionTimeout, this); 93 //添加節點授權 94 zk.addAuthInfo(authentication_type,correctAuthentication.getBytes()); 95 System.out.println(LOG_PREFIX_OF_MAIN + "開始連接ZK服務器"); 96 //倒數等待 97 connectedSemaphore.await(); 98 } catch (Exception e) { 99 e.printStackTrace(); 100 } 101 } 102 103 /** 104 * 關閉ZK連接 105 */ 106 public void releaseConnection() { 107 if (this.zk!=null) { 108 try { 109 this.zk.close(); 110 } catch (InterruptedException e) { 111 } 112 } 113 } 114 115 /** 116 * 117 * <B>方法名稱:</B>測試函數<BR> 118 * <B>概要說明:</B>測試認證<BR> 119 * @param args 120 * @throws Exception 121 */ 122 public static void main(String[] args) throws Exception { 123 124 ZookeeperAuth testAuth = new ZookeeperAuth(); 125 testAuth.createConnection(CONNECT_ADDR,2000); 126 List<ACL> acls = new ArrayList<ACL>(1); 127 for (ACL ids_acl : Ids.CREATOR_ALL_ACL) { 128 acls.add(ids_acl); 129 } 130 131 try { 132 zk.create(PATH, "init content".getBytes(), acls, CreateMode.PERSISTENT); 133 System.out.println("使用授權key:" + correctAuthentication + "創建節點:"+ PATH + ", 初始內容是: init content"); 134 } catch (Exception e) { 135 e.printStackTrace(); 136 } 137 try { 138 zk.create(PATH_DEL, "will be deleted! ".getBytes(), acls, CreateMode.PERSISTENT); 139 System.out.println("使用授權key:" + correctAuthentication + "創建節點:"+ PATH_DEL + ", 初始內容是: init content"); 140 } catch (Exception e) { 141 e.printStackTrace(); 142 } 143 144 // 獲取數據 145 getDataByNoAuthentication(); 146 getDataByBadAuthentication(); 147 getDataByCorrectAuthentication(); 148 149 // 更新數據 150 updateDataByNoAuthentication(); 151 updateDataByBadAuthentication(); 152 updateDataByCorrectAuthentication(); 153 154 // 刪除數據 155 deleteNodeByBadAuthentication(); 156 deleteNodeByNoAuthentication(); 157 deleteNodeByCorrectAuthentication(); 158 // 159 Thread.sleep(1000); 160 161 deleteParent(); 162 //釋放連接 163 testAuth.releaseConnection(); 164 } 165 /** 獲取數據:采用錯誤的密碼 */ 166 static void getDataByBadAuthentication() { 167 String prefix = "[使用錯誤的授權信息]"; 168 try { 169 ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null); 170 //授權 171 badzk.addAuthInfo(authentication_type,badAuthentication.getBytes()); 172 Thread.sleep(2000); 173 System.out.println(prefix + "獲取數據:" + PATH); 174 System.out.println(prefix + "成功獲取數據:" + badzk.getData(PATH, false, null)); 175 } catch (Exception e) { 176 System.err.println(prefix + "獲取數據失敗,原因:" + e.getMessage()); 177 } 178 } 179 180 /** 獲取數據:不采用密碼 */ 181 static void getDataByNoAuthentication() { 182 String prefix = "[不使用任何授權信息]"; 183 try { 184 System.out.println(prefix + "獲取數據:" + PATH); 185 ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null); 186 Thread.sleep(2000); 187 System.out.println(prefix + "成功獲取數據:" + nozk.getData(PATH, false, null)); 188 } catch (Exception e) { 189 System.err.println(prefix + "獲取數據失敗,原因:" + e.getMessage()); 190 } 191 } 192 193 /** 采用正確的密碼 */ 194 static void getDataByCorrectAuthentication() { 195 String prefix = "[使用正確的授權信息]"; 196 try { 197 System.out.println(prefix + "獲取數據:" + PATH); 198 199 System.out.println(prefix + "成功獲取數據:" + zk.getData(PATH, false, null)); 200 } catch (Exception e) { 201 System.out.println(prefix + "獲取數據失敗,原因:" + e.getMessage()); 202 } 203 } 204 205 /** 206 * 更新數據:不采用密碼 207 */ 208 static void updateDataByNoAuthentication() { 209 210 String prefix = "[不使用任何授權信息]"; 211 212 System.out.println(prefix + "更新數據: " + PATH); 213 try { 214 ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null); 215 Thread.sleep(2000); 216 Stat stat = nozk.exists(PATH, false); 217 if (stat!=null) { 218 nozk.setData(PATH, prefix.getBytes(), -1); 219 System.out.println(prefix + "更新成功"); 220 } 221 } catch (Exception e) { 222 System.err.println(prefix + "更新失敗,原因是:" + e.getMessage()); 223 } 224 } 225 226 /** 227 * 更新數據:采用錯誤的密碼 228 */ 229 static void updateDataByBadAuthentication() { 230 231 String prefix = "[使用錯誤的授權信息]"; 232 233 System.out.println(prefix + "更新數據:" + PATH); 234 try { 235 ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null); 236 //授權 237 badzk.addAuthInfo(authentication_type,badAuthentication.getBytes()); 238 Thread.sleep(2000); 239 Stat stat = badzk.exists(PATH, false); 240 if (stat!=null) { 241 badzk.setData(PATH, prefix.getBytes(), -1); 242 System.out.println(prefix + "更新成功"); 243 } 244 } catch (Exception e) { 245 System.err.println(prefix + "更新失敗,原因是:" + e.getMessage()); 246 } 247 } 248 249 /** 250 * 更新數據:采用正確的密碼 251 */ 252 static void updateDataByCorrectAuthentication() { 253 254 String prefix = "[使用正確的授權信息]"; 255 256 System.out.println(prefix + "更新數據:" + PATH); 257 try { 258 Stat stat = zk.exists(PATH, false); 259 if (stat!=null) { 260 zk.setData(PATH, prefix.getBytes(), -1); 261 System.out.println(prefix + "更新成功"); 262 } 263 } catch (Exception e) { 264 System.err.println(prefix + "更新失敗,原因是:" + e.getMessage()); 265 } 266 } 267 268 /** 269 * 不使用密碼 刪除節點 270 */ 271 static void deleteNodeByNoAuthentication() throws Exception { 272 273 String prefix = "[不使用任何授權信息]"; 274 275 try { 276 System.out.println(prefix + "刪除節點:" + PATH_DEL); 277 ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null); 278 Thread.sleep(2000); 279 Stat stat = nozk.exists(PATH_DEL, false); 280 if (stat!=null) { 281 nozk.delete(PATH_DEL,-1); 282 System.out.println(prefix + "刪除成功"); 283 } 284 } catch (Exception e) { 285 System.err.println(prefix + "刪除失敗,原因是:" + e.getMessage()); 286 } 287 } 288 289 /** 290 * 采用錯誤的密碼刪除節點 291 */ 292 static void deleteNodeByBadAuthentication() throws Exception { 293 294 String prefix = "[使用錯誤的授權信息]"; 295 296 try { 297 System.out.println(prefix + "刪除節點:" + PATH_DEL); 298 ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null); 299 //授權 300 badzk.addAuthInfo(authentication_type,badAuthentication.getBytes()); 301 Thread.sleep(2000); 302 Stat stat = badzk.exists(PATH_DEL, false); 303 if (stat!=null) { 304 badzk.delete(PATH_DEL, -1); 305 System.out.println(prefix + "刪除成功"); 306 } 307 } catch (Exception e) { 308 System.err.println(prefix + "刪除失敗,原因是:" + e.getMessage()); 309 } 310 } 311 312 /** 313 * 使用正確的密碼刪除節點 314 */ 315 static void deleteNodeByCorrectAuthentication() throws Exception { 316 317 String prefix = "[使用正確的授權信息]"; 318 319 try { 320 System.out.println(prefix + "刪除節點:" + PATH_DEL); 321 Stat stat = zk.exists(PATH_DEL, false); 322 if (stat!=null) { 323 zk.delete(PATH_DEL, -1); 324 System.out.println(prefix + "刪除成功"); 325 } 326 } catch (Exception e) { 327 System.out.println(prefix + "刪除失敗,原因是:" + e.getMessage()); 328 } 329 } 330 331 /** 332 * 使用正確的密碼刪除節點 333 */ 334 static void deleteParent() throws Exception { 335 try { 336 Stat stat = zk.exists(PATH_DEL, false); 337 if (stat == null) { 338 zk.delete(PATH, -1); 339 } 340 } catch (Exception e) { 341 e.printStackTrace(); 342 } 343 } 344 345 }
