以前章節介紹了zookeeper集羣的自動化啓動腳本,本節博主將帶你們簡單的使用zookeeper的java客戶端API,從而瞭解其使用。java
zookeeper監聽器原理:node
zookeeper使用步驟:linux
(1)新建maven項目em-zookeeper-testapache
(2)解壓以前在linux系統中安裝集羣的zookeeper安裝包到E:\zookeeper-3.4.13\,打開E:\zookeeper-3.4.13\dist-maven目錄查看pom文件centos
(3)按照以上信息在em-zookeeper-test項目的pom中加入zookeeper服務器/客戶端(目前客戶端和服務端是合在一塊兒的)依賴。服務器
pom.xmlsession
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.empire.zookeeper.test</groupId> <artifactId>em-zookeeper</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>em-zookeeper</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.13</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> <showWarnings>true</showWarnings> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.21.0</version> <inherited>true</inherited> <configuration> <!-- <skip>true</skip> --> <forkMode>once</forkMode> <argLine>-Dfile.encoding=UTF-8</argLine> </configuration> </plugin> <!-- 拷貝依賴的jar包到lib目錄 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <!-- ${project.build.directory} 構建目錄,缺省爲target --> <outputDirectory> ${project.build.directory}/lib </outputDirectory> </configuration> </execution> </executions> </plugin> <!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <archive> <manifest> <mainClass></mainClass> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> </manifest> </archive> <classesDirectory> </classesDirectory> </configuration> </plugin> --> </plugins> </build> </project>
(4)zookeeperzookeeper的java客戶端API使用案例app
package com.empire.zookeeper.test.em_zookeeper; import java.util.List; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; import org.junit.Before; import org.junit.Test; public class SimpleZkClient { private static final String connectString = "centos-aaron-07:2181,centos-aaron-08:2181,centos-aaron-16:2181"; private static final int sessionTimeout = 1000; private CountDownLatch connectedSemaphore = new CountDownLatch(1); ZooKeeper zkClient = null; @Before public void init() throws Exception { zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() { public void process(WatchedEvent event) { // 收到事件通知後的回調函數(應該是咱們本身的事件處理邏輯) System.out.println(event.getType() + "---" + event.getPath()); try { zkClient.getChildren("/", true); //Decrements the count of the latch, releasing all waiting threads if the count reaches zero. connectedSemaphore.countDown(); } catch (Exception e) { } } }); //Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted. connectedSemaphore.await(); //Thread.currentThread().sleep(10000); } /** * 數據的增刪改查 * * @throws InterruptedException * @throws KeeperException */ // 建立數據節點到zk中 @Test public void testCreate() throws KeeperException, InterruptedException { // 參數1:要建立的節點的路徑 參數2:節點大數據 參數3:節點的權限 參數4:節點的類型 String nodeCreated = zkClient.create("/eclipse", "hellozk".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); //上傳的數據能夠是任何類型,但都要轉成byte[] } //判斷znode是否存在 @Test public void testExist() throws Exception{ Stat stat = zkClient.exists("/eclipse", false); System.out.println(stat==null?"not exist":"exist"); } // 獲取子節點 @Test public void getChildren() throws Exception { List<String> children = zkClient.getChildren("/", true); for (String child : children) { System.out.println(child); } //Thread.sleep(Long.MAX_VALUE); } //獲取znode的數據 @Test public void getData() throws Exception { byte[] data = zkClient.getData("/eclipse", false, null); System.out.println(new String(data)); } //刪除znode @Test public void deleteZnode() throws Exception { //參數2:指定要刪除的版本,-1表示刪除全部版本 zkClient.delete("/eclipse", -1); } //刪除znode @Test public void setData() throws Exception { zkClient.setData("/app1", "imissyou angelababy".getBytes(), -1); byte[] data = zkClient.getData("/app1", false, null); System.out.println(new String(data)); } }
(5)日誌配置(zookeeper須要打印日誌)less
### set log levels ### log4j.rootLogger = debug , stdout , D , E ### \u8F93\u51FA\u5230\u63A7\u5236\u53F0 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n ### \u8F93\u51FA\u5230\u65E5\u5FD7\u6587\u4EF6 ### log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = logs/log.log log4j.appender.D.Append = true ## \u8F93\u51FADEBUG\u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7 log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n ### \u4FDD\u5B58\u5F02\u5E38\u4FE1\u606F\u5230\u5355\u72EC\u6587\u4EF6 ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender ## \u5F02\u5E38\u65E5\u5FD7\u6587\u4EF6\u540D log4j.appender.E.File = logs/error.log log4j.appender.E.Append = true ## \u53EA\u8F93\u51FAERROR\u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7!!! log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
(6)問題思考(在沒加鎖以前很容易報錯)eclipse
org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /eclipse at org.apache.zookeeper.KeeperException.create(KeeperException.java:102) at org.apache.zookeeper.KeeperException.create(KeeperException.java:54) at org.apache.zookeeper.ZooKeeper.exists(ZooKeeper.java:1111) at org.apache.zookeeper.ZooKeeper.exists(ZooKeeper.java:1139) at com.empire.zookeeper.test.em_zookeeper.SimpleZkClient.testExist(SimpleZkClient.java:57) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
該問題主要時因爲zookeeper的內部實現機制產生的,由於在項目中建立zookeeper鏈接時,同時建立了connect、listener兩個線程,connet用於數據發送傳遞,而listener用於監聽zookeeper的下發通知,且listener線程是做爲connect線程的守護線程工做的。因爲zookeeper在建立鏈接時會花非不少時間以及資源,故在建立過程當中,就已經返回了鏈接對象,該鏈接對象須要在zookeeper向客戶端發送了鏈接建立成功的通知SyncConnected事件後纔可以使用,因此此處咱們能夠加一把鎖CountDownLatch來實現業務代碼暫停等待。
最後寄語,以上是博主本次文章的所有內容,若是你們以爲博主的文章還不錯,請點贊;若是您對博主其它服務器技術或者博主本人感興趣,請關注博主博客,而且歡迎隨時跟博主溝通交流。