服務註冊:
當provider啓動的時候,連接zk集羣,便會在zk集羣中創建瞬時節點。將自己的url保存到瞬時節點中。
當provider出現宕機,某個服務器的url就會減少,瞬時節點就會自動減少。該服務器重啓回覆正常,便會重新生成瞬時節點,將該服務器存儲的url又重新添加到zk集羣中。
服務發現:
當consumer啓動的時候,連接zk集羣,會獲得所有瞬時節點的集合。將其混存到本地的集合中去。
通過負載均衡算法將產生一個可以訪問的服務進行訪問。當provider發生宕機的情況,consumer會重新進行讀取zk集羣的列表,重新加載url,將其保存在本地的集合中。
代碼實現:
情景: 3個服務器發佈三個url地址到zookeeper集羣中,當一臺服務器關閉(項目),zookeeper便會刪除該項目的url(瞬時節點),並重新進行讀取。
5.1.1創建zk-rmi-cluseter-provider(jar)項目
5.1.2添加依賴
<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.bjsxt.zk.rmi</groupId>
<artifactId>zk-rmi-cluster-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 添加公共資源依賴 -->
<dependency>
<groupId>com.bjsxt.resources</groupId>
<artifactId>rmi-resources</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- zk的api依賴 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
</dependencies>
</project>
5.1.3拷貝OrdersServiceImpl實現類
5.1.4創建ProviderApp實現服務發佈和註冊
package com.bjsxt.app;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import com.bjsxt.service.OrdersService;
import com.bjsxt.service.impl.OrdersServiceImpl;
import org.apache.zookeeper.ZooKeeper;
public class ProviderApp {
//實現線程同步
private CountDownLatch latch=new CountDownLatch(1);
/***
* 建立和zk集羣的建立
*/
public ZooKeeper getConnection() {
ZooKeeper zk=null;
try {
zk=new ZooKeeper(Constants.ZK_HOST, Constants.TIME_OUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 判斷是否和zk集羣建立鏈接
if(event.getState()==Event.KeeperState.SyncConnected) {
latch.countDown(); //喚醒阻塞的線程
}
}
});
//阻塞主線程
latch.await();
}catch(Exception ex) {
ex.printStackTrace();
}
return zk;
}
/***
* 創建瞬時的,順序節點,同時將自己的url寫入到瞬時節點
*/
public void providerRegister(String url) {
try {
ZooKeeper zk=getConnection();
if(zk!=null) {
//創建瞬時,順序節點
zk.create(Constants.URL, //指定的節點路徑,注意自己手動創建/provider
url.getBytes(), //節點中保存的數據
Ids.OPEN_ACL_UNSAFE, //權限
CreateMode.EPHEMERAL_SEQUENTIAL);//節點類型
}
}catch(Exception ex) {
ex.printStackTrace();
}
}
/***
* 實現服務的發佈
*/
public void pulisher(Integer port) {
try {
//指定暴露的遠程服務的訪問端口
LocateRegistry.createRegistry(port);
//創建OrdersServiceImpl實現類
OrdersService remote=new OrdersServiceImpl();
//定義遠程訪問的url
String name="rmi://localhost:"+port+"/sxt";
//進行給remote對象綁定一個遠程訪問的地址
Naming.bind(name, remote);
//調用服務的註冊方法,完成服務註冊
providerRegister(name);
System.out.println("==========發佈遠程服務===========9999");
}catch(Exception ex) {
ex.printStackTrace();
}
}
/***
* 發佈集羣服務
*/
public static void main(String[] args) {
ProviderApp app=new ProviderApp();
app.pulisher(9999);
}
}
5.1.5查看發佈結果、
5.2.1創建zk-rmi-cluster-consumer(jar)項目
5.2.2添加依賴
<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.bjsxt.zk.rmi.consumer</groupId>
<artifactId>zk-rmi-cluster-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 添加公共資源依賴 -->
<dependency>
<groupId>com.bjsxt.resources</groupId>
<artifactId>rmi-resources</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- zk的api依賴 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
</dependencies>
</project>
5.2.3拷貝Constants接口
5.2.4創建ConsumerApp啓動發現和消費服務
package com.bjsxt.app;
import java.rmi.ConnectException;
import java.rmi.Naming;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import com.bjsxt.pojo.Orders;
import com.bjsxt.service.OrdersService;
/***
* 實現服務的發現和消費
* @author EDZ
*
*/
public class ConsumerApp {
//緩存可用的服務地址列表
private volatile List<String> urls=new ArrayList<>();
//實現線程同步
private CountDownLatch latch=new CountDownLatch(1);
/***
* 建立和zk集羣的建立
*/
public ZooKeeper getConnection() {
ZooKeeper zk=null;
try {
zk=new ZooKeeper(Constants.ZK_HOST, Constants.TIME_OUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 判斷是否和zk集羣建立鏈接
if(event.getState()==Event.KeeperState.SyncConnected) {
latch.countDown(); //喚醒阻塞的線程
}
}
});
//阻塞主線程
latch.await();
}catch(Exception ex) {
ex.printStackTrace();
}
return zk;
}
/***
* 讀取zk集羣中註冊的服務
*/
public void providerFetch() {
try {
ZooKeeper zk=getConnection();
if(zk!=null) {
//讀取/provider接下的所有子節點
List<String> children = zk.getChildren(Constants.PROVIDER, new Watcher() {
/***
* 觀察/provider節點的子節點是否有變化
*/
@Override
public void process(WatchedEvent event) {
// TODO Auto-generated method stub
if(event.getType()==Event.EventType.NodeChildrenChanged) {
System.out.println("========子節點發生變化========");
providerFetch(); //如果有子節點變化,回調重新讀取
}
}
});
//保存讀取的服務地址
List<String> path=new ArrayList<>();
//遍歷子節點集合children
for(String node:children) {
//System.out.println(node);
//獲得node節點中的數據
byte[] data = zk.getData(Constants.PROVIDER+"/"+node, false, null);
//byte[]轉化爲String
String url=new String(data);
path.add(url);
}
this.urls=path;
}
}catch(Exception ex) {
ex.printStackTrace();
}
}
/***
* 完成服務消費
*/
public void consumer() {
while (true) {
try {
// 產生一個隨機數
int index = ThreadLocalRandom.current().nextInt(this.urls.size());
// 遠程服務的訪問地址
String name = this.urls.get(index);
// 獲得遠程服務的代理對象
OrdersService remote = (OrdersService) Naming.lookup(name);
// 獲得會員訂單的集合
List<Orders> list = remote.loadOrdersList(111111);
for (Orders orders : list) {
System.out.println(orders.getId() + "\t"
+ orders.getVip() + "\t" + orders.getOdate() + "\t"
+ orders.getRemark());
}
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 無參數構造方法
*/
public ConsumerApp() {
providerFetch();
}
public static void main(String[] args) {
ConsumerApp app=new ConsumerApp();
app.consumer();
}
}