搭建ZooKeeper服務注冊中心
上傳文件:
zookeeper-3.4.9.tar.gz
解壓zookeeper-3.4.9.tar.gz
將/opt/zookeeper-3.4.9/conf/zoo_sample.cfg復制為/opt/zookeeper-3.4.9/conf/zoo.cfg
新建目錄:/opt/zookeeper-3.4.9/data
修改/opt/zookeeper-3.4.9/conf/zoo.cfg文件
# the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/opt/zookeeper-3.4.9/data
啟動ZooKeeper:
[root@right bin]# pwd /opt/zookeeper-3.4.9/bin [root@right bin]# ./zkServer.sh start ZooKeeper JMX enabled by default Using config: /opt/zookeeper-3.4.9/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [root@right bin]# ./zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/zookeeper-3.4.9/bin/../conf/zoo.cfg Mode: standalone
永久關閉防火牆:
chkconfig iptables off
舉例子說明:
創建服務端工程:
引入依賴:
<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.soyoungboy.distribute</groupId>
<artifactId>DubboConsumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.soyoungboy.distribute</groupId>
<artifactId>DubboInterfaces</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
創建服務接口的實現類
import com.alibaba.dubbo.demo.DemoService; public class DemoServiceImpl implements DemoService { public String sayHello(String name) { return "Hello " + name; } }
Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 配置當前應用模塊名稱 --> <dubbo:application name="demo-provider"/> <!-- 配置注冊中心的位置 --> <!-- Multicast 注冊中心:multicast://224.5.6.7:1234 --> <!-- 配置ZooKeeper注冊中心位置方式如下 --> <dubbo:registry address="192.168.159.200:2181" protocol="zookeeper"/> <!-- 配置Dubbo客戶端的訪問端口 --> <dubbo:protocol name="dubbo" port="20880"/> <!-- 配置接口實現類對應的bean --> <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/> <!-- 配置提供的服務的接口 --> <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/> </beans>
log4j.properties
log4j.rootLogger=DEBUG,myConsole
log4j.appender.myConsole=org.apache.log4j.ConsoleAppender
log4j.appender.myConsole.ImmediateFlush=true
log4j.appender.myConsole.Target=System.out
log4j.appender.myConsole.layout=org.apache.log4j.PatternLayout
log4j.appender.myConsole.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
創建客戶端工程:DubboConsumer
引入依賴:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.5</version> </dependency> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.10.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.soyoungboy.distributed</groupId> <artifactId>ServiceInterface</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 配置當前應用模塊名稱 --> <dubbo:application name="demo-consumer"/> <!-- 配置注冊中心位置 --> <dubbo:registry address="192.168.159.246:2181" protocol="zookeeper"/> <!-- 配置提供服務的接口類型 --> <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService"/> <context:component-scan base-package="com.soyoungboy.distribute.handler"/> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:annotation-driven/> <mvc:default-servlet-handler/> </beans>
在需要調用服務的bean中注入接口類型的bean
import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.alibaba.dubbo.demo.DemoService; @Controller public class SayHelloHandler { @Autowired private DemoService demoService; @RequestMapping("/testSayHello") public String sayHello(Map<String, Object> map) { //像調用本地方法一樣調用遠程服務 String sayHello = demoService.sayHello("Tom"); map.put("result", sayHello); return "result"; } }
ZooKeeper
ZooKeeper=文件系統+通知機制
文件系統:ZooKeeper使用樹形結構管理數據。而且以“/”作為樹形結構的根節點。
通知機制:用ZooKeeper的通知機制后,各個模塊工程在特定znode上設置Watcher(觀察者)來監控當前節點上值的變化。一旦Watcher檢測到了數據變化就會立即通知模塊工程,從而自動實現“一處修改,處處生效”的效果。
常用命令:
啟動服務器:./zkServer.sh start 停止服務器:./zkServer.sh stop 啟動客戶端:./zkCli.sh 退出客戶端:[zk: localhost:2181(CONNECTED) 6] quit
ls:查看當前znode中所包含的內容
ls2:查看當前節點數據並能看到更新次數等數據
stat:查看節點狀態 stat /tebieshuai
set:設置節點的具體值
set 節點 value值 set /tebieshuai new_value
get:獲得節點的值 get /shuai
get節點
delete:可以刪除指定znode,當該znode擁有子znode時,必須先刪除其所有子znode,否則操作將失敗。
rmr:命令可用於代替delete命令,rmr是一個遞歸刪除命令,如果發生指定節點擁有子節點時,rmr命令會首先刪除子節點。
rmr /chou000000008
create:
create [-s] [-e] path data acl
普通創建:不帶有-s、-e參數
-s:含有序列 create -s /chou true
-e:臨時(重啟或者超時消失)create -s -e /templ uuu
stat屬性內容:
czxid:引起這個znode創建的zxid,創建節點的事務的zxid(ZooKeeper Transaction Id)
ctime:znode被創建的毫秒數(從1970年開始)
mzxid:znode最后更新的zxid
mtime:znode最后修改的毫秒數(從1970年開始)
pZxid:znode最后更新的子節點zxid
cversion:znode子節點變化號,znode子節點修改次數
dataversion:znode數據變化號
aclVersion:znode訪問控制列表的變化號
ephemeralOwner:如果是臨時節點,這個是znode擁有者的session id。如果不是臨時節點則是0。
dataLength:znode的數據長度
numChildren:znode子節點數量
ZooKeeper四字命令:
ruok:測試服務是否處於正確狀態。如果確實如此,那么服務返回“imok ”,否則不做任何響應
stat:輸出關於性能和連接的客戶端的列表
conf:輸出相關服務配置的詳細信息
cons:列出所有連接到服務器的客戶端的完全的連接 /會話的詳細信息。包括“接受 / 發送”的包數量、會話id 、操作延遲、最后的操作執行等等信息
dump:列出未經處理的會話和臨時節點
envi:輸出關於服務環境的詳細信息(區別於conf命令)
reqs:列出未經處理的請求
wchs:列出服務器watch的詳細信息
wchc:通過session列出服務器watch的詳細信息,它的輸出是一個與watch相關的會話的列表
wchp:通過路徑列出服務器 watch的詳細信息。它輸出一個與 session相關的路徑
通過Java程序操作Zookeeper
依賴信息:
<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.soyoungboy.zookeeper</groupId> <artifactId>ZooKeeper</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.10</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.9</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> </dependencies> </project>
Java操作代碼:
import java.io.IOException; import java.util.ArrayList; 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.ACL; import org.apache.zookeeper.data.Stat; public class NodeOperation { /** * 設置節點值 * @param zooKeeper * @param path * @param nodeData * @return * @throws KeeperException * @throws InterruptedException */ public Stat setNodeData(ZooKeeper zooKeeper, String path, String nodeData) throws KeeperException, InterruptedException { Stat stat = zooKeeper.setData(path, nodeData.getBytes(), -1); return stat; } /** * 獲取指定節點上的數據 * @param zooKeeper * @param path * @return * @throws KeeperException * @throws InterruptedException */ public String getNodeData(ZooKeeper zooKeeper, String path) throws KeeperException, InterruptedException { byte[] data = zooKeeper.getData(path, false, new Stat()); return new String(data); } /** * 創建節點 * @param zooKeeper ZooKeeper服務器連接對象 * @param path 要創建的節點的路徑 * @param nodeData 節點的數據 * @return * @throws KeeperException * @throws InterruptedException */ public String createNewNode(ZooKeeper zooKeeper, String path, String nodeData) throws KeeperException, InterruptedException { //將字符串類型的數據轉換為字節數組類型 byte[] nodeDataBytes = nodeData.getBytes(); //訪問控制列表 ArrayList<ACL> openAclUnsafe = Ids.OPEN_ACL_UNSAFE; //創建模式 CreateMode mode = CreateMode.PERSISTENT; //執行創建 String result = zooKeeper.create(path, nodeDataBytes, openAclUnsafe, mode); return result; } /** * 連接ZooKeeper服務器 * @return * @throws IOException */ public ZooKeeper connectToZookeeper() throws IOException { //連接ZooKeeper服務器的信息 String connectString = "192.168.159.200:2181"; int sessionTimeout = 50 * 1000; //創建ZooKeeper對象 ZooKeeper zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() { @Override public void process(WatchedEvent event) { //暫時不做任何處理 } }); return zooKeeper; } }
測試使用代碼:
import java.io.IOException; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; import org.junit.Test; import com.atguigu.zookeeper.NodeOperation; public class ZooKeeperTest { private NodeOperation nodeOperation = new NodeOperation(); private ZooKeeper zooKeeper = null; @Test public void testSetNodeData() throws KeeperException, InterruptedException { Stat stat = nodeOperation.setNodeData( zooKeeper, "/shuai", "are you ok"); System.out.println(stat); int cversion = stat.getCversion(); System.out.println(cversion); } @Test public void testGetNodeData() throws KeeperException, InterruptedException { String nodeData = nodeOperation.getNodeData(zooKeeper, "/shuai"); System.out.println(nodeData); } @Test public void testCreateNode() throws KeeperException, InterruptedException { //create /aaa com.atguigu.service String path = "/aaa"; String nodeData = "com.atguigu.service"; String result = nodeOperation.createNewNode(zooKeeper, path, nodeData); System.out.println(result); } { try { zooKeeper = nodeOperation.connectToZookeeper(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } } @Test public void testConnection() throws IOException, InterruptedException { ZooKeeper zooKeeper = nodeOperation.connectToZookeeper(); System.out.println(zooKeeper); Thread.sleep(Long.MAX_VALUE); } }
通知機制
使用方法的遞歸調用實現持續觀察
代碼實現:
public class MyWatchMulti { public static void main(String[] args) throws IOException, KeeperException, InterruptedException { final ZooKeeper zooKeeper = new ZooKeeper("192.168.159.200:2181", 50 * 1000, new Watcher() { @Override public void process(WatchedEvent event) {} }); byte[] nodeData = zooKeeper.getData("/notify", new Watcher() { //回調:由系統或其他對象調用我們寫的方法,而不是像平時我們自己調用自己寫的方法 public void process(WatchedEvent event) { System.err.println("*********接收到通知了[第一次]***********"); MyWatchMulti multi = new MyWatchMulti(); //調用遞歸方法持續觀察 String currentValue = multi.recursionGetData(zooKeeper); System.err.println("當前值="+currentValue); System.err.println("*********接收到通知了[第一次]***********"); } }, new Stat()); System.out.println(new String(nodeData)); Thread.sleep(Long.MAX_VALUE); } /** * 以遞歸方式執行獲取數據和設置觀察者操作實現持續觀察 * @param zooKeeper * @return */ public String recursionGetData(final ZooKeeper zooKeeper) { byte[] currentValue = null; try { currentValue = zooKeeper.getData("/notify", new Watcher() { @Override public void process(WatchedEvent event) { //遞歸調用的核心 recursionGetData(zooKeeper); } }, new Stat()); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } String currentResult = new String(currentValue); System.out.println("遞歸中獲取的值="+currentResult); return currentResult; } }