zookeeper
Zookeeper 實戰
主要內容
Zookeeper 簡介
Zookeeper 儲存結構
監聽通知
安裝 Zookeeper
Zookeeper 常用命令
使用 Java API 操作 Zookeeper
Zookeeper 實戰
學習目標
一、 Zookeeper 簡介
1 什麼是 Zookeeper
Zookeeper 官網: http://zookeeper.apache.org/
Zookeeper 是 Apache 的一個分散式服務框架,是 Apache Hadoop 的一個子專案。官方文件上這麼解釋 Zookeeper,它主要是用來解決分散式應用中經常遇到的一些資料管理問題,
如:統一命名服務、狀態同步服務、叢集管理、分散式應用配置項的管理等。
簡單來說 zookeeper=檔案系統+監聽通知機制。
二、 Zookeeper 儲存結構
1 Znode
在 Zookeeper 中,znode 是一個跟 Unix 檔案系統路徑相似的節點,可以向節點儲存資料或者獲取資料。
Zookeeper 底層是一套資料結構。這個儲存結構是一個樹形結構,其上的每一個節點,我們稱之為“znode”
Zookeeper 中的資料是按照“樹”結構進行儲存的。而且 znode 節點還分為 4 種不同的型別。
每一個 znode 預設能夠儲存 1MB 的資料(對於記錄狀態性質的資料來說,夠了)可以使用 zkCli 命令,登入到 Zookeeper 上,並通過 ls、create、delete、get、set等命令操作這些 znode 節點。
2 Znode 節點型別
2.1 PERSISTENT-持久化目錄節點
客戶端與 zookeeper 斷開連線後,該節點依舊存在。
2.2 PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點
客戶端與 zookeeper 斷開連線後,該節點依舊存在,只是 Zookeeper 給該節點名稱進行順序編號。
2.3 EPHEMERAL-臨時目錄節點
客戶端與 zookeeper 斷開連線後,該節點被刪除。
2.4 EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點
客戶端與 zookeeper 斷開連線後,該節點被刪除,只是 Zookeeper 給該節點名稱進行順序編號。
三、 監聽通知機制
Zookeeper 是使用觀察者設計模式來設計的。當客戶端註冊監聽它關心的目錄節點時,
當目錄節點發生變化(資料改變、被刪除、子目錄節點增加刪除)時,Zookeeper 會通知客戶端。
四、 安裝 zookeeper
官方資源包可在 zookeeper.apache.com 站點中下載。最新發布版本為:3.6.0。
安裝很簡單,解壓就可以用,但需要配置
1 安裝單機版
1.1 安裝 Linux
1.2 安裝 JDK
配置環境變數
export JAVA_HOME=/usr/local/jdk
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH
1.3 上傳 Zookeeper
1.4解壓 Zookeeper 壓縮包
拷貝到/usr/local/ 目錄下
1.5Zookeeper 目錄結構
logs目錄是啟動之後才會有的,記錄日誌
1. bin:放置執行指令碼和工具指令碼,
2. conf:zookeeper 預設讀取配置的目錄,裡面會有預設的配置檔案
3. docs:zookeeper 相關的文件
4. lib:zookeeper 核心的 jar
5. logs:zookeeper 日誌
1.6配置 Zookeeper
建立zookeeper執行時資料快取目錄
Zookeeper 在啟動時預設的去 conf 目錄下查詢一個名稱為 zoo.cfg 的配置檔案。
在 zookeeper 應用目錄中有子目錄 conf。其中有配置檔案模板:zoo_sample.cfg
cp zoo_sample.cfg zoo.cfg==(將 zoo_sample.cfg檔案拷貝到當前目錄下改名為zoo.cfg 因為zoo.cfg 是zookeeper預設去找的配置檔案)==。zookeeper 應用中的配置檔案為 conf/zoo.cfg。
修改 zoo.cfg配置檔案
clientPort:監聽客戶端連線的埠號預設為2181
dataDir : 設定zookeeper執行時資料快取目錄位置
1.7啟動 Zookeeper
預設載入配置檔案:./zkServer.sh start:預設的會去 conf 目錄下載入 zoo.cfg 配置檔案。
指定載入配置檔案:./zkServer.sh start 配置檔案的路徑。
啟動成功
檢視zookeeper當前狀態 zkServer.sh status
1.8停止 Zookeeper
./zkServer.sh stop
1.9檢視 Zookeeper 狀態
./zkServer.sh status
關於執行BUG:
zookeeper啟動之後會生成logs目錄用於記錄日誌
1.10使用客戶端連線單機版 Zookeeper
1.10.1 連線方式一
bin/zkCli.sh
預設連線地址為本機地址,預設連線埠為 2181
拒絕連線的原因是zookeeper還沒有啟動
啟動zookeeper
連線成功
現在在zookeeper下有一個結點
按Ctrl+C 退出連線
1.10.2 連線方式二
bin/zkCli.sh -server ip:port
連線指定 IP 地址與埠
eg:
連線成功
2 安裝叢集版
2.1Zookeeper 叢集說明
2.1.1 Zookeeper 叢集中的角色
Zookeeper 叢集中的角色主要有以下三類
在建立zookeeper叢集之前所有的結點都是跟隨者,但是一旦通過內部的投票選舉演算法選出一個領導者之後,除了領導者之外每一個跟隨者都是一個zookeeper的結點,當跟隨者結點的資料發生變化時會通知領導者,領導者再去通知其他的跟隨者,從發生資料變化的結點中做資料同步
2.2叢集安裝
使用 3 個 Zookeeper 應用搭建一個偽叢集(在一個Linux系統中搭建叢集)。應用部署位置是:192.168.88.101。
客戶端監聽埠分別為:2181、2182、2183。投票選舉埠分別為 2881/3881、2882/3882、2883/3883。
投票和選舉用的是兩個埠
建立存放zookeeper叢集例項的目錄
tar -zxf zookeeper-3.6.0.tar.gz
將解壓後的 Zookeeper 應用目錄重新命名,便於管理
mv zookeeper-3.6.0 zookeeper01
2.2.1 提供資料快取目錄
在 zookeeper01 應用目錄中,建立 data 目錄,用於快取應用執行資料
cd zookeeper01
mkdir data
2.2.2 複製應用
複製兩份 Zookeeper 應用。用於模擬叢集中的 3 個節點。此時複製的Zookeeper應用帶data目錄
cp -r zookeeper01 zookeeper02
cp -r zookeeper01 zookeeper03
現在相當於安裝好了三個Zookeeper例項了
2.2.3 提供配置檔案
在 zookeeper 應用目錄中有子目錄 conf。其中有配置檔案模板:zoo_sample.cfg
cp zoo_sample.cfg zoo.cfg
zookeeper 應用中的配置檔案為 conf/zoo.cfg。
2.2.4 修改配置檔案 zoo.cfg - 設定資料快取路徑
dataDir 引數值為應用執行快取資料儲存目錄。
Zookeeper01
Zookeeper02
Zookeeper03
2.2.5 提供應用唯一標識
***在 Zookeeper 叢集中,每個節點需要一個唯一標識。***這個唯一標識要求是自然數。且唯一標識儲存位置是:資料快取目錄(dataDir=/usr/local/zookeeper/data)的 myid (data目錄中沒有需要自己建立,且必須叫myid)檔案中。其中“資料快取目錄”為配置檔案 zoo.cfg 中的配置引數
在 data 目錄中建立檔案 myid : touch myid
為應用提供唯一標識。本環境中使用 1、2、3 作為每個節點的唯一標識。
vi myid
簡化方式為: echo [唯一標識] >> myid。
echo 命令為回聲命令,系統會將命令傳送的資料返回。 '>>'為定位,代表系統回聲資料指定傳送到什麼位置。 此命令代表系統回聲資料傳送到 myid 檔案中。 如果沒有檔案則建立檔案。
自動幫助建立myid檔案
繼續標識Zookeeper02和Zookeeper03
2.2.6 修改配置檔案 zoo.cfg - 設定監聽客戶端、投票、選舉埠
vim zoo.cfg
server.1標識定位Zookeeper01這個例項 server.X X的值取決於例項中myid檔案裡面的值
192.168.88.101 是例項所在主機的IP地址 後面跟的是投票和選舉埠
clientPort=2181 #服務埠根據應用做對應修改,zk01-2181,zk02-2182,zk03-2183
server.1=192.168.88.101:2881:3881
server.2=192.168.88.101:2882:3882
server.3=192.168.88.101:2883:3883
修改三個Zookeeper例項的配置檔案
Zookeeper01 客戶端監聽埠為 2181
Zookeeper02 客戶端監聽埠改為 2182
Zookeeper03 客戶端監聽埠改為 2183
測試啟動三個Zookeeper例項 Zookeeper會自動建立叢集
叢集建立成功 檢視各個結點的狀態,領導者和跟隨者 觀察者會在兩個跟隨者之間選一個,看不見
2.3編寫啟動、關閉叢集指令碼
在 Linux 中可以使用 chmod 命令為檔案授權。
chmod 777 檔名
777 表示為檔案分配可讀,可寫,可執行許可權。
2.3.1 啟動 Zookeeper 叢集指令碼
zookeeper01/bin/zkServer.sh start
zookeeper02/bin/zkServer.sh start
zookeeper03/bin/zkServer.sh start
給startall.sh檔案分配可執行許可權
可讀可寫可執行
執行這個集中啟動的檔案 三個Zookeeper例項都執行了
2.3.2 關閉 Zookeeper 叢集指令碼
zookeeper01/bin/zkServer.sh stop
zookeeper02/bin/zkServer.sh stop
zookeeper03/bin/zkServer.sh stop
建立集中關閉的檔案 shutdownall.sh
分配可讀可寫可執行許可權
執行集中關閉的可執行檔案 三個Zookeeper例項都被關閉了
2.4連線叢集
可以使用任何節點中的客戶端工具連線叢集中的任何節點。
./zkCli.sh -server 192.168.88.101:2183
客戶端工具是誰無所謂,不管在不在叢集裡面都可以連線叢集
先啟動再連線,用Zookeeper01連線Zookeeper03
啟動
連線
連線成功
用單機Zookeeper連線叢集Zookeeper中的結點
五、Zookeeper 常用命令
1 ls 命令
ls /path
使用 ls 命令檢視 zookeeper 中的內容。在 ZooKeeper 控制檯客戶端中,沒有預設列表功能,
必須指定要列表資源的位置。 如: ls / 或者 ls /path
必須給個路徑
檢視根下 根下有個Zookeeper的結點
檢視Zookeeper下有哪些結點
檢視config下有哪些結點 config下沒有任何結點了
2 create 命令
create [-e] [-s] /path [data]
path:指定在哪個位置建立結點 data:建立結點時新增的資料
使用 create 命令建立一個新的 Znode。create [-e] [-s] path data - 建立節點,
如: create /test 123 建立一個/test 節點(不加任何引數預設為持久型別的結點在客戶端斷開連線時不會被刪除),節點攜帶資料資訊 123。
create -e /test 123 建立一個臨時節點/test,攜帶資料為 123,
臨時節點只在當前會話生命週期中有效,會話結束節點自動刪除。
create -s /test 123 建立一個順序節點/test,攜帶資料 123,
建立的順序節點由 ZooKeeper 自動為節點增加字尾資訊,如-/test00000001 等。-e 和-s 引數可以聯合使用。
在根下建立結點bjsxt
先退出連結再連結,bjsxt這個結點還在 不給任何引數預設為持久型別的
-s 表示建立一個帶序號的持久化結點 結點的值為123 0000000001為結點的序號
-e 表示建立一個臨時結點 不給值
臨時結點退出客戶端連線之後就會被刪除,不是立即刪除需要等待幾秒鐘 temp結點已被刪除
建立一個臨時的帶序號的結點
退出重新連線客戶端之後臨時結點被刪除
3 get 命令
get [-s] /path
get 命令獲取 Znode 中的資料。
get -s /path
-s 檢視 Znode 詳細資訊
lzc:存放的資料
cZxid:建立時 zxid(znode 每次改變時遞增的事務 id)
ctime:建立時間戳
mZxid:最近一次更近的 zxid
mtime:最近一次更新的時間戳
pZxid:子節點的 zxid
cversion:子節點更新次數
dataversion:節點資料更新次數
aclVersion:節點 ACL(授權資訊)的更新次數
ephemeralOwner:如果該節點為 ephemeral 節點(臨時,生命週期與 session 一樣),
ephemeralOwner 值表示與該節點繫結的 session id. 如果該節點不是
ephemeral 節點, ephemeralOwner 值為 0.
dataLength:節點資料位元組數
numChildren:子節點數量
4 set 命令
set /path [data]
新增或修改 Znode 中的值
修改結點bjsxt的值為AAA
建立一個空結點,然後通過set命令給結點賦值
5 delete 命令
delete /path
刪除 Znode。
test結點已被刪除
六、 使用 Java API 操作 Zookeeper
1 建立 Znode
1.1建立專案
1.2修改 POM 檔案新增依賴
該依賴為基於 Java 語言連線 Zookeeper 的客戶端工具
依賴版本應和按照的Zookeeper版本保持一致
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.0</version>
</dependency>
1.3建立 Znode 並新增資料
前四個常量含義依次為:
建立許可權
對當前操作開放所有許可權
讀取許可權
只對當前客戶端開放所有許可權
package com.bjsxt;
import org.apache.zookeeper.*;
import java.io.IOException;
/**
* 操作Zookeeper的Znode
*/
public class ZnodeDemo implements Watcher {
public static void main(String[] args) throws KeeperException, InterruptedException, IOException {
//建立連線Zookeeper物件 這個物件是有新增的依賴jar包提供的
/**
* param1:給定當前去連結Zookeeper的IP地址和埠,連線Zookeeper叢集則用逗號分隔
* param2:客戶端工具在連結Zookeeper的超時時間
* param3:Zookeeper提供的做事件通知的處理器,對Zookeeper做事件操作Zookeeper會把事件傳遞到程式碼中,需要實現Watcher介面
* 在Watcher介面下有process()方法,採用回撥的方式將事件行為通知給程式碼
*/
ZooKeeper zooKeeper = new ZooKeeper("192.168.88.101:2181,192.168.88.101:2182,192.168.88.101:2183", 150000, new ZnodeDemo());
//建立一個Znode create方法的返回值是建立Znode的路徑
/**
* param1:建立Znode的位置
* param2:為Znode新增的值,必須是位元組陣列型別
* param3:許可權設定
* param4:建立Znode的型別(4種型別)
*/
String path = zooKeeper.create("/bjsxt/test", "lzc".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
System.out.println(path);
}
/**
* 事件通知回撥方法
* @param watchedEvent
* 一旦有時間產生Zookeeper會呼叫process方法通知
*/
@Override
public void process(WatchedEvent watchedEvent) {
//獲取連結事件
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
System.out.println("連線成功!");
}
}
}
建立成功 在bjsxt結點下建立有序子節點test
2 獲取 Znode 中的資料
2.1獲取指定節點中的資料
package com.bjsxt;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
/**
* 操作Zookeeper的Znode
*/
public class ZnodeDemo implements Watcher {
public static void main(String[] args) throws KeeperException, InterruptedException, IOException {
//建立連線Zookeeper物件 這個物件是有新增的依賴jar包提供的
/**
* param1:給定當前去連結Zookeeper的IP地址和埠,連線Zookeeper叢集則用逗號分隔
* param2:客戶端工具在連結Zookeeper的超時時間
* param3:Zookeeper提供的做事件通知的處理器,對Zookeeper做事件操作Zookeeper會把事件傳遞到程式碼中,需要實現Watcher介面
* 在Watcher介面下有process()方法,採用回撥的方式將事件行為通知給程式碼
*/
ZooKeeper zooKeeper = new ZooKeeper("192.168.88.101:2181,192.168.88.101:2182,192.168.88.101:2183", 150000, new ZnodeDemo());
//建立一個Znode create方法的返回值是建立Znode的路徑
/**
* param1:建立Znode的位置
* param2:為Znode新增的值,必須是位元組陣列型別
* param3:許可權設定
* param4:建立Znode的型別(4種型別)
*/
/*String path = zooKeeper.create("/bjsxt/test", "lzc".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
System.out.println(path);*/
//獲取指定結點的資料 返回一個byte[]型別的位元組陣列
/**
* param1:獲取資料的結點路徑
* param2:回撥處理器
* param3:能夠返回節點的餓統計資訊
*/
byte[] data = zooKeeper.getData("/bjsxt/test0000000000", new ZnodeDemo(), new Stat());
//得先將位元組陣列轉換成String型別做字串轉換才能列印
System.out.println(new String(data));
}
/**
* 事件通知回撥方法
* @param watchedEvent
* 一旦有時間產生Zookeeper會呼叫process方法通知
*/
@Override
public void process(WatchedEvent watchedEvent) {
//獲取連結事件
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
System.out.println("連線成功!");
}
}
}
2.2獲取所有子節點中的資料
//獲取指定結點中的所有子節點中的資料 返回結果為list list中存放的是根據當前結點下所有子節點的路徑
/**
* param1:取哪個結點的子節點的路徑
* param2:回撥處理器
*/
List<String> list = zooKeeper.getChildren("/bjsxt", new ZnodeDemo());
//遍歷子節點路徑
for (String path : list) {
//取某個結點的值得給完整的路徑所以得拼接上跟路徑 stat也可以不給,給個null就行
byte[] data = zooKeeper.getData("/bjsxt/" + path, new ZnodeDemo(), null);
System.out.println(new String(data));
}
}
bjsxt下只有一個子節點
3 設定 Znode 中的值
/**
* param1:給定需要設定值的結點的路徑
* param2:需要設定的值 需要一個byte[]型別陣列
* param3:版本匹配 給 -1 表示忽略版本匹配任何版本都可以
*/
Stat stat = zooKeeper.setData("/bjsxt/test0000000000", "bjsxt".getBytes(), -1);
System.out.println(stat);
資料發生改變
4 刪除 Znode
//刪除Znode中的值
/**
* param1:需要刪除結點的路徑
* param2:版本匹配 給 -1 表示忽略版本匹配任何版本都可以
*/
zooKeeper.delete("/bjsxt/test0000000000",-1);
刪除成功
package com.bjsxt;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.List;
/**
* 操作Zookeeper的Znode
*/
public class ZnodeDemo implements Watcher {
public static void main(String[] args) throws KeeperException, InterruptedException, IOException {
//建立連線Zookeeper物件 這個物件是有新增的依賴jar包提供的
/**
* param1:給定當前去連結Zookeeper的IP地址和埠,連線Zookeeper叢集則用逗號分隔
* param2:客戶端工具在連結Zookeeper的超時時間
* param3:Zookeeper提供的做事件通知的處理器,對Zookeeper做事件操作Zookeeper會把事件傳遞到程式碼中,需要實現Watcher介面
* 在Watcher介面下有process()方法,採用回撥的方式將事件行為通知給程式碼
*/
ZooKeeper zooKeeper = new ZooKeeper("192.168.88.101:2181,192.168.88.101:2182,192.168.88.101:2183", 150000, new ZnodeDemo());
//建立一個Znode create方法的返回值是建立Znode的路徑
/**
* param1:建立Znode的位置
* param2:為Znode新增的值,必須是位元組陣列型別
* param3:許可權設定
* param4:建立Znode的型別(4種型別)
*/
/*String path = zooKeeper.create("/bjsxt/test", "lzc".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
System.out.println(path);*/
//獲取指定結點的資料 返回一個byte[]型別的位元組陣列
/**
* param1:獲取資料的結點路徑
* param2:回撥處理器
* param3:能夠返回節點的餓統計資訊
*/
/*byte[] data = zooKeeper.getData("/bjsxt/test0000000000", new ZnodeDemo(), new Stat());
//得先將位元組陣列轉換成String型別做字串轉換才能列印
System.out.println(new String(data));*/
//獲取指定結點中的所有子節點中的資料 返回結果為list list中存放的是根據當前結點下所有子節點的路徑
/**
* param1:取哪個結點的子節點的路徑
* param2:回撥處理器
*/
/*List<String> list = zooKeeper.getChildren("/bjsxt", new ZnodeDemo());
//遍歷子節點路徑
for (String path : list) {
//取某個結點的值得給完整的路徑所以得拼接上跟路徑 stat也可以不給,給個null就行
byte[] data = zooKeeper.getData("/bjsxt/" + path, new ZnodeDemo(), null);
System.out.println(new String(data));
}*/
//設定Znode中的值 返回stat型別是當前結點詳細資訊的物件
/**
* param1:給定需要設定值的結點的路徑
* param2:需要設定的值 需要一個byte[]型別陣列
* param3:版本匹配 給 -1 表示忽略版本匹配任何版本都可以
*/
/*Stat stat = zooKeeper.setData("/bjsxt/test0000000000", "bjsxt".getBytes(), -1);
System.out.println(stat);*/
//刪除Znode中的值
/**
* param1:需要刪除結點的路徑
* param2:版本匹配 給 -1 表示忽略版本匹配任何版本都可以
*/
zooKeeper.delete("/bjsxt/test0000000000",-1);
}
/**
* 事件通知回撥方法
* @param watchedEvent
* 一旦有時間產生Zookeeper會呼叫process方法通知
*/
@Override
public void process(WatchedEvent watchedEvent) {
//獲取連結事件
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
System.out.println("連線成功!");
}
}
}
七、 Zookeeper 實戰
實戰案例介紹:使用 Zookeeper 與 RMI 技術實現一個 RPC 框架。
RPC:RPC(Remote Procedure Call)遠端過程呼叫。
1 基於 RMI 實現遠端方法呼叫
1.1RMI 簡 介
RMI(Remote Method Invocation) 遠端方法呼叫。
RMI 是從 JDK1.2 推出的功能,它可以實現在一個 Java 應用中可以像呼叫本地方法一樣 呼叫另一個伺服器中 Java 應用(JVM)中的內容。
RMI 是 Java 語言的遠端呼叫,無法實現跨語言。
1.2執行流程
Server:被呼叫者
Client:呼叫者
Registry:登錄檔
Server端允許外界應用通過Server端物件呼叫Server端的方法(物件的暴露),如果不暴露這個物件只能在當前Server端使用,暴露需要使用bind()或者rebind()方法把這個物件繫結到一個登錄檔中,登錄檔有Server端提供,登錄檔中放的是所有暴露的物件,Client如果想通過Server中的物件呼叫某一個方法Client需要拿到Server端的登錄檔,再通過lookup()方法從登錄檔中找到需要的物件,然後Client拿著找到的物件呼叫Server下的方法
Registry(登錄檔)是放置所有伺服器物件的名稱空間。 每次服務端建立一個物件時,它都會使用 bind()或 rebind()方法註冊該物件。 這些是使用稱為繫結名稱的唯一名稱註冊的。
**要呼叫遠端物件,客戶端需要該物件的引用。**即通過服務端繫結的名稱從登錄檔中獲取物件(lookup()方法)。
1.3RMI 的 API 介紹
1.3.1 Remote 介面
java.rmi.Remote 定義了此介面為遠端呼叫介面。如果介面被外部呼叫,需要繼承此介面。
1.3.2 RemoteException 類
java.rmi.RemoteException
繼承了 Remote 介面的介面,如果方法是允許被遠端呼叫的,需要丟擲此異常。
1.3.3 UnicastRemoteObject 類
java.rmi.server.UnicastRemoteObject
此類實現了 Remote 介面和 Serializable 介面。
自定義介面實現類除了實現自定義介面還需要繼承此類。
1.3.4 LocateRegistry 類
java.rmi.registry.LocateRegistry
可以通過 LocateRegistry 在本機上建立 Registry,通過特定的埠就可以訪問這個Registry。
1.3.5 Naming 類
java.rmi.Naming
Naming 定義了釋出內容可訪問 RMI 名稱。也是通過 Naming 獲取到指定的遠端方法。
1.4建立 Server 端
1.4.1 建立專案
建立空專案
新增模組
建立maven型別工程
1.4.2 建立介面
package com.bjsxt.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 允許遠端呼叫介面,該介面必須要實現Remote介面
* 允許被遠端呼叫的方法必須要丟擲RemoteException異常
*/
public interface DemoService extends Remote {
String demo(String str) throws RemoteException;
}
1.4.3 建立介面實現類
需要將構造方法的修飾型別由 protected改成public
package com.bjsxt.service.impl;
import com.bjsxt.service.DemoService;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 介面實現類必須要繼承UnicastRemoteObject
* 會自動新增構造方法,需要修改為public
*/
public class DemoServiceImpl extends UnicastRemoteObject implements DemoService {
//UnicastRemoteObject下有三個構造方法保留一個即可
public DemoServiceImpl() throws RemoteException {
}
@Override
public String demo(String str) throws RemoteException {
return "Hello RMI"+str;
}
}
1.4.4 編寫主方法
package com.bjsxt;
import com.bjsxt.service.DemoService;
import com.bjsxt.service.impl.DemoServiceImpl;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class DemoServer {
public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
//將物件例項化
DemoService demoService = new DemoServiceImpl();
//建立本地登錄檔 指定訪問該登錄檔的埠號為8888
LocateRegistry.createRegistry(8888);
//將物件繫結到登錄檔上 rmi:表示未來查詢物件是通過rmi協議查詢 localhost:當前server所在主機IP
//第一個demoService是作為被繫結物件的唯一標識,一般用被繫結物件名稱
Naming.bind("rmi://localhost:8888/demoService",demoService);
}
}
啟動之後程式處於阻塞狀態,說明createRegistry在監聽8888埠,等著外界呼叫demoServer物件
1.5建立 Client 端
1.5.1 建立專案
1.5.2 複製服務端介面
package com.bjsxt.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 允許遠端呼叫介面,該介面必須要實現Remote介面
* 允許被遠端呼叫的方法必須要丟擲RemoteException異常
*/
public interface DemoService extends Remote {
String demo(String str) throws RemoteException;
}
1.5.3 建立主方法
package com.bjsxt;
import com.bjsxt.service.DemoService;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class ClientDemo {
public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {
DemoService demoService = (DemoService) Naming.lookup("rmi://localhost:8888/demoService");
String result = demoService.demo("北京尚學堂");
System.out.println(result);
}
}
2 使用 Zookeeper 作為註冊中心實現 RPC
以Zookeeper作為註冊中心,rmiServer在啟動時除了要把地址註冊到本地登錄檔中還要把地址放到Zookeeper的一個Znode裡面儲存,rmiClient在啟動時去連結Zookeeper找到存放地址的結點通過getDate()方法獲取地址的值,然後將獲取的地址交給lookup()方法,lookup()再去連結本地登錄檔拿到物件然後通過物件呼叫rmiServer裡面的方法
2.1建立服務端
2.1.1 建立專案
2.1.2 修改 POM 檔案新增依賴
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.0</version>
</dependency>
2.1.3 建立介面
package com.bjsxt.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface UsersService extends Remote {
String findUsers(String str) throws RemoteException;
}
2.1.4 建立介面實現類
package com.bjsxt.service.impl;
import com.bjsxt.service.UsersService;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class UsersServiceImpl extends UnicastRemoteObject implements UsersService {
//只保留一個無引數的構造方法即可 將protect改為public
public UsersServiceImpl() throws RemoteException {
}
@Override
public String findUsers(String str) throws RemoteException {
return "Hello Zookeeper " + str;
}
}
2.1.5 編寫主方法
package com.bjsxt;
import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class serverDemo implements Watcher {
public static void main(String[] args) throws IOException, AlreadyBoundException, KeeperException, InterruptedException {
//例項化對外暴露的物件
UsersService usersService = new UsersServiceImpl();
//將物件繫結到本地的登錄檔中 建立一個本地的登錄檔監聽8888埠
LocateRegistry.createRegistry(8888);
String url = "rmi://localhost:8888/user";
//url為繫結標識 完成繫結
Naming.bind(url, usersService);
//將url放到Zookeeper的結點中
ZooKeeper zooKeeper = new ZooKeeper("192.168.88.101:2181,192.168.88.101:2182,192.168.88.101:2183",150000,new serverDemo());
//建立結點 並且將url放到Znode中
zooKeeper.create("/bjsxt/service", url.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("服務釋出成功!!!");
}
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
System.out.println("連結成功!!!");
}
}
}
2.2建立客戶端
2.2.1 建立專案
2.2.2 修改 POM 檔案新增依賴
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.0</version>
</dependency>
2.2.3 建立介面
package com.bjsxt.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface UsersService extends Remote {
String findUsers(String str) throws RemoteException;
}
2.2.4 編寫主方法
package com.bjsxt;
import com.bjsxt.service.UsersService;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
public class ClientDemo implements Watcher {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException, NotBoundException {
//連結Zookeeper
ZooKeeper zooKeeper = new ZooKeeper("192.168.88.101:2181,192.168.88.101:2182,192.168.88.101:2183", 150000, new ClientDemo());
//將Zookeeper當成註冊中心從來裡面取出來的
byte[] bytes = zooKeeper.getData("/bjsxt/service", new ClientDemo(), null);
//將位元組陣列轉換成String型別
String url = new String(bytes);
System.out.println(url);
//找物件
UsersService usersService = (UsersService) Naming.lookup(url);
//通過拿到的物件呼叫方法
String result = usersService.findUsers("百戰程式設計師 Zookeeper作為註冊中心");
System.out.println(result);
}
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
System.out.println("連結成功!!!");
}
}
}
相關文章
- 【zookeeper】zookeeper分散式鎖分散式
- 【Zookeeper】zookeeper客戶端KeeperErrorCode = ConnectionLoss客戶端Error
- 【zookeeper之七】Zookeeper客戶端客戶端
- ZooKeeper 06 - ZooKeeper 的常用命令
- ZooKeeper 系列(一)—— ZooKeeper核心概念詳解
- zookeeper學習04 zookeeper收尾+dubbo前瞻
- Zookeeper原始碼分析(二) —– zookeeper日誌原始碼
- Zookeeper原始碼分析(二) ----- zookeeper日誌原始碼
- Zookeeper系列一:Zookeeper基礎命令操作
- zookeeper理解
- zookeeper:spark-project專案的zookeeper配置SparkProject
- [Zookeeper-01]什麼是zookeeper?& Linux / Windows Zookeeper安裝和部署(單點)LinuxWindows
- ZooKeeper筆記(1):ZooKeeper特性與基本概念筆記
- ZooKeeper系列(4):ZooKeeper的配置檔案詳解
- ZooKeeper系列(2):ZooKeeper命令列工具zkCli.sh命令列
- Zookeeper 新手教程
- ZooKeeper淺談
- zookeeper控制檯
- zookeeper總結
- zookeeper入門
- Java呼叫ZookeeperJava
- zookeeper使用教程
- Zookeeper簡介
- Zookeeper深入原理
- zookeeper、dubbo、kafkaKafka
- 分散式-zookeeper分散式
- ZooKeeper系列(三)
- ZooKeeper系列(四)
- dubbo 和 zookeeper
- ZooKeeper介紹
- 【GO】27. zookeeper golang庫go-zookeeper例項Golang
- Zookeeper原始碼分析-Zookeeper Leader選舉演算法原始碼演算法
- ZooKeeper 05 - ZooKeeper 叢集的腦裂問題(Split Brain)AI
- ZooKeeper分散式專題(一) -- zookeeper安裝以及介紹分散式
- ZooKeeper系列(3)--基於ZooKeeper實現主從協作
- ZooKeeper 入門教程
- Zookeeper叢集搭建
- Kafka——zookeeper的作用Kafka