ZooKeeper編程01--RMI服務的多服務器管理


服務器端與客戶端都要用到:

public interface ZkInfo {String ZK_CONNECTION_STRING = "192.168.1.201:2181,192.168.1.202:2181,192.168.1.203:2181";int ZK_SESSION_TIMEOUT = 5000;String ZK_REGISTRY_PATH = "/registry";String ZK_PROVIDER_PATH = ZK_REGISTRY_PATH + "/provider";
}
import java.rmi.Remote;
import java.rmi.RemoteException;public interface MyService extends Remote {String showInfo(String name) throws RemoteException;
}


服務器端

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Calendar;public class MyServiceImpl extends UnicastRemoteObject implements MyService{/*** */private static final long serialVersionUID = 8329425460319055273L;protected MyServiceImpl() throws RemoteException {}public String showInfo(String name) throws RemoteException {String h = "";try {InetAddress host = Inet4Address.getLocalHost();h = host.getHostAddress();} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();}Calendar c = Calendar.getInstance();return h + " " + c.getTime().toString() + name;}}



import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
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;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class ServiceProvider {private static final Logger LOGGER = LoggerFactory.getLogger(ServiceProvider.class);//用於等待SyncConnected事件觸發後繼續執行當前進程private CountDownLatch latch = new CountDownLatch(1);//發佈RMI服務並註冊RMI地址到ZooKeeper中public void publish(Remote remote, String host, int port){String url = publishService(remote, host, port);//發佈RMI服務並返回RMI地址if (url != null){ZooKeeper zk = connectServer();//連接ZooKeeper服務器並獲取ZooKeeper對象if (zk != null){createNode(zk, url); //創建ZNode並將RMI地址放入ZNode上}}}//發佈RMI服務private String publishService(Remote remote, String host, int port){String url = null;try{url = String.format("rmi://%s:%d/%s", host, port, remote.getClass().getName());LocateRegistry.createRegistry(port);Naming.rebind(url, remote);LOGGER.debug("publish rmi service(url: {})", url);} catch(RemoteException | MalformedURLException e) {LOGGER.error("", e);}return url;}//連接ZooKeeper服務器private ZooKeeper connectServer(){ZooKeeper zk = null;try{zk = new ZooKeeper(ZkInfo.ZK_CONNECTION_STRING, ZkInfo.ZK_SESSION_TIMEOUT, new Watcher(){@Overridepublic void process(WatchedEvent event){if (event.getState() == Event.KeeperState.SyncConnected){latch.countDown();//喚醒當前正在執行的線程}}});if (zk.exists(ZkInfo.ZK_REGISTRY_PATH, false) == null)zk.create(ZkInfo.ZK_REGISTRY_PATH, " ".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);latch.await(); //使當前進程處於等待狀態} catch (IOException | InterruptedException | KeeperException e){LOGGER.error("", e);}return zk;}//創建ZNodeprivate void createNode(ZooKeeper zk, String url){try{byte[] data = url.getBytes();//創建一個臨時性且有序的ZNodeString path = zk.create(ZkInfo.ZK_PROVIDER_PATH, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);LOGGER.debug("create zookeeper node ({} => {})", path, url);} catch (KeeperException | InterruptedException e){LOGGER.error("", e);}}
}

//ZooKeeper版本
public class Server {public static void main(String[] args) throws Exception{if (args.length != 2){System.err.println("please using command: java Server <rmi_host> <rmi_port>");System.exit(-1);}String host = args[0];int port = Integer.parseInt(args[1]);ServiceProvider provider = new ServiceProvider();MyServiceImpl myService = new MyServiceImpl();provider.publish(myService, host, port);Thread.sleep(Long.MAX_VALUE);}
}

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;//無ZooKeeper版本
public class RmiServer {public static void main(String[] args) throws Exception{int port = 1099;String url = "rmi://localhost:1099/MyServiceImpl";LocateRegistry.createRegistry(port);Naming.rebind(url, new MyServiceImpl());}
}

客戶端

import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.ConnectException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class ServiceConsumer {private static final Logger LOGGER = LoggerFactory.getLogger(ServiceConsumer.class);//用於等待SyncConnected事件觸發後繼續執行當前進程private CountDownLatch latch = new CountDownLatch(1);// 定義一個 volatile 成員變量,用于保存最新的 RMI 地址(考慮到該變量或許會被其它線程所修改,一旦修改后,該變量的值會影響到所有線程)// volatile讓變量每次在使用的時候,都從主存中取。而不是從各個線程的“工作內存”。// volatile具有synchronized關鍵字的“可見性”,但是沒有synchronized關鍵字的“并發正確性”,也就是說不保證線程執行的有序性。// 也就是說,volatile變量對于每次使用,線程都能得到當前volatile變量的最新值。但是volatile變量并不保證并發的正確性。private volatile List<String> urlList = new ArrayList<>();//連接ZooKeeper服務器private ZooKeeper connectServer(){ZooKeeper zk = null;try {zk = new ZooKeeper(ZkInfo.ZK_CONNECTION_STRING, ZkInfo.ZK_SESSION_TIMEOUT, new Watcher(){@Overridepublic void process(WatchedEvent event){if (event.getState() == Event.KeeperState.SyncConnected){latch.countDown();//喚醒當前正在執行的線程}}});latch.await();//使當前線程處於等待狀態} catch (IOException | InterruptedException e){LOGGER.error("", e);}return zk;}//觀察/registry節點下所有子節點是否有變化private void watchNode(final ZooKeeper zk){try{List<String> nodeList = zk.getChildren(ZkInfo.ZK_REGISTRY_PATH, new Watcher(){@Overridepublic void process(WatchedEvent event){if (event.getType() == Event.EventType.NodeChildrenChanged){watchNode(zk);//若子節點有變化,則重新調用該方法(爲了獲取最新子節點中的數據)}}});List<String> dataList = new ArrayList<>();//用於存放/registry所有子節點中的 數據for (String node : nodeList){byte[] data = zk.getData(ZkInfo.ZK_REGISTRY_PATH + "/" + node, false, null); //獲取/registry的子節點中的數據dataList.add(new String(data));}LOGGER.debug("node data: {}", dataList);urlList = dataList; // 更新最新的 RMI 地址} catch (KeeperException | InterruptedException e){LOGGER.error("", e);}}//構造器public ServiceConsumer(){ZooKeeper zk = connectServer();//連接ZooKeeper服務器並獲取ZooKeeper對象if (zk != null){watchNode(zk);//觀察/registry節點的所有子節點並更新urlList成員變量}}//在JNDI中查找RMI遠程服務對象@SuppressWarnings("unchecked")private <T> T lookupService(String url){T remote = null;try{remote = (T) Naming.lookup(url);} catch (NotBoundException | MalformedURLException | RemoteException e){if ( e instanceof ConnectException){//若連接中斷,則使用urlList中第一個RMI地址來查找(這是一種簡單的重試方式,確保不會拋出異常)LOGGER.error("ConnectException -> url: {}", url);if (urlList.size() != 0){url = urlList.get(0);return lookupService(url);}}LOGGER.error("", e);}return remote;}//查找RMI服務public <T extends Remote> T lookup(){T service = null;int size = urlList.size();if (size > 0){String url;if (size == 1){url = urlList.get(0); //若urlList中只有一個元素,則直接獲取該元素LOGGER.debug("using only url: {}", url);} else {url = urlList.get(ThreadLocalRandom.current().nextInt(size));//若urlList中存在多個元素,則隨機獲取一個元素LOGGER.debug("using random url: {}", url);System.out.println(url);}service = lookupService(url);}return service;}
}

//含ZooKeeper版本
public class Client {public static void main(String[] args) throws Exception{ServiceConsumer consumer = new ServiceConsumer();//zookeeper測試while (true){MyService myService = consumer.lookup();String result = myService.showInfo("test");System.out.println(result);Thread.sleep(3000);}}
}

import java.rmi.Naming;//無ZooKeeper版本
public class RmiClient {public static void main(String[] args) throws Exception{String url = "rmi://localhost:1099/MyServiceImpl";MyService myService = (MyService)Naming.lookup(url);String result = myService.showInfo("jinzhao");System.out.println(result);}
}


log4j.properties

# Define some default values that can be overridden by system properties
zookeeper.root.logger=INFO, CONSOLE
zookeeper.console.threshold=INFO
zookeeper.log.dir=.
zookeeper.log.file=zookeeper.log
zookeeper.log.threshold=DEBUG
zookeeper.tracelog.dir=.
zookeeper.tracelog.file=zookeeper_trace.log#
# ZooKeeper Logging Configuration
## Format is "<default threshold> (, <appender>)+# DEFAULT: console appender only
log4j.rootLogger=${zookeeper.root.logger}# Example with rolling log file
#log4j.rootLogger=DEBUG, CONSOLE, ROLLINGFILE# Example with rolling log file and tracing
#log4j.rootLogger=TRACE, CONSOLE, ROLLINGFILE, TRACEFILE#
# Log INFO level and above messages to the console
#
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=${zookeeper.console.threshold}
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n#
# Add ROLLINGFILE to rootLogger to get log file output
#    Log DEBUG level and above messages to a log file
log4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLINGFILE.Threshold=${zookeeper.log.threshold}
log4j.appender.ROLLINGFILE.File=${zookeeper.log.dir}/${zookeeper.log.file}# Max log file size of 10MB
log4j.appender.ROLLINGFILE.MaxFileSize=10MB
# uncomment the next line to limit number of backup files
#log4j.appender.ROLLINGFILE.MaxBackupIndex=10log4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n#
# Add TRACEFILE to rootLogger to get log file output
#    Log DEBUG level and above messages to a log file
log4j.appender.TRACEFILE=org.apache.log4j.FileAppender
log4j.appender.TRACEFILE.Threshold=TRACE
log4j.appender.TRACEFILE.File=${zookeeper.tracelog.dir}/${zookeeper.tracelog.file}log4j.appender.TRACEFILE.layout=org.apache.log4j.PatternLayout
### Notice we are including log4j's NDC here (%x)
log4j.appender.TRACEFILE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L][%x] - %m%n


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387133.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387133.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387133.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

org.activiti.engine.ActivitiOptimisticLockingException updated by another transaction concurrently

org.activiti.engine.ActivitiOptimisticLockingException: Task[id5905010, name審核(市場部)] was updated by another transaction concurrentlyat org.activiti.engine.impl.db.DbSqlSession.flushUpdates(DbSqlSession.java:872)at org.activiti.engine.impl.db.DbSqlSess…

DataTable不能通過已刪除的行訪問該行的信息解決方法

使用dt.Rows[0]["name", DataRowVersion.Original]可以獲取轉載于:https://www.cnblogs.com/heyiping/p/10616640.html

ZooKeeper編程02--多線程的分佈式鎖

面向過程版&#xff1a; package distributedLockProcess;import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zoo…

01 Python變量和數據類型

Python變量和數據類型 1 數據類型 計算機&#xff0c;顧名思義就是可以做數學計算的機器&#xff0c;因此&#xff0c;計算機程序理所當然也可以處理各種數值。 但是&#xff0c;計算機能處理的遠不止數值&#xff0c;還可以處理文本、圖形、音頻、視頻、網頁等各種各樣的數…

初識Python-1

1&#xff0c;計算機基礎。 2&#xff0c;python歷史。 宏觀上&#xff1a;python2 與 python3 區別&#xff1a; python2 源碼不標準&#xff0c;混亂&#xff0c;重復代碼太多&#xff0c; python3 統一 標準&#xff0c;去除重復代碼。 3&#xff0c;python的環境。 編譯型&…

02 List、Tuple、Dict、Set

List 線性表 創建List&#xff1a; >>> classmates [Michael, Bob, Tracy] >>> L [Michael, 100, True] #可以在list中包含各種類型的數據 >>> empty_list [] #空List 按索引訪問List&#xff1a; >>> print L[0] #索引從0開始…

Jenkins的一些代碼

pipeline {agent anyenvironment { def ITEMNAME "erp"def DESTPATH "/home/ops/testpipe"def codePATH"/var/lib/jenkins/workspace/test_pipeline"}stages { stage(代碼拉取){steps {echo "checkout from ${ITEMNAME}"git url:…

利用layui前端框架實現對不同文件夾的多文件上傳

利用layui前端框架實現對不同文件夾的多文件上傳 問題場景&#xff1a; 普通的input標簽實現多文件上傳時&#xff0c;只能對同一個文件夾下的多個文件進行上傳&#xff0c;如果要同時上傳兩個或多個文件夾下的文件&#xff0c;是無法實現的。這篇文章就是利用layui中的插件&am…

ps、grep和kill聯合使用殺掉進程

ps、grep和kill聯合使用殺掉進程例如要殺掉hello這個進程&#xff0c;使用下面這個命令就能直接實現。ps -ef |grep hello |awk {print $2}|xargs kill -9這里是輸出ps -ef |grep hello 結果的第二列的內容然后通過xargs傳遞給kill -9,其實第二列內容就是hello的進程號&#xf…

03 控制語句

if語句 if age > 18 print your age is, age else print teenager Python代碼的縮進規則&#xff1a;具有相同縮進的代碼被視為代碼塊。 if age > 18 print adult elif age > 6 print teenager elif age > 3 print kid else print baby for循環 L [Adam, L…

yum 來安裝 nodejs

要通過 yum 來安裝 nodejs 和 npm 需要先給 yum 添加 epel 源&#xff0c;添加方法在 centos 添加epel和remi源 中##添加 epel 源 64位: rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm32位: rpm -ivh http://download.fedoraproj…

yzh的神仙題

U66905 zz題 考慮一個點權值被計算了多少次。。。不知 所以對未來承諾&#xff0c;方便直接算上總數&#xff01; 然后其實是給邊定向&#xff0c;即先刪除fa和son的哪一個 f[x][j]&#xff0c;會計算j次 無法轉移 f[x][j][k]&#xff0c;其中會從子樹計算k次。 當邊從兒子指向…

04 函數

內置函數 Python內置了很多有用的函數&#xff0c;可以直接調用。 要調用一個函數&#xff0c;需要知道函數的名稱和參數。 可以直接從Python的官方網站查看文檔&#xff1a;http://docs.python.org/2/library >>> abs(-20) >>> help(abs) >>>…

iview render的時候可以寫控件的基本格式

render: (h, params) > {return h(div, [h(Button, {props: {type: id,size: small},style: {marginRight: 5px},on: {click: () > {this.pojectshow(this.datatable[params.index].id)}}}, 詳情),h(Button, {props: {type: id,size: small},style: {marginRight: 5px},o…

ES6基本使用

var let 度可用于聲明變量. 區別&#xff1a;1、let&#xff1a;只在let命令所在代碼塊內有效 2、let 不存在變量提升&#xff08;內部影響不到外部&#xff09; var b [];for(var j0;j<10;j){let dj;b[j]function(){console.log(d);};}b[3]() //3 3、let 不允許在相同作用…

Axios的Vue插件(添加全局請求/響應攔截器)

/*** file Axios的Vue插件&#xff08;添加全局請求/響應攔截器&#xff09;*/// https://github.com/mzabriskie/axios import axios from axios// 攔截request,設置全局請求為ajax請求 axios.interceptors.request.use((config) > {config.headers[X-Requested-With] XML…

05 切片、迭代、列表生成

切片 >>> L [Adam, Lisa, Bart, Paul] >>> L[0:3] #取前3個元素 >>> L[:3] >>> L[1:3] >>> L[:] >>> L[::2] #第三個參數表示每2個元素取一個元素&#xff0c;也就是隔一個取一個 [Adam,Bart] >>>…

一個例子徹底搞懂C++的虛函數和純虛函數

學習C的多態性&#xff0c;你必然聽過虛函數的概念&#xff0c;你必然知道有關她的種種語法&#xff0c;但你未必了解她為什么要那樣做&#xff0c;未必了解她種種行為背后的所思所想。深知你不想在流于表面語法上的蜻蜓點水似是而非&#xff0c;今天我們就一起來揭開擋在你和虛…

利用Caffe實現mnist的數據訓練

阿里云的參考文檔&#xff1a;https://help.aliyun.com/document_detail/49571.html在文檔里提供了caffe的一個案例&#xff0c;利用Caffe實現mnist的數據訓練。準備的數據源可以在“深度學習案例代碼及數據下載”頁找到Caffe數據下載并解壓。要訓練自己的圖片&#xff0c;還是…

06 函數式編程

1 函數式編程簡介 函數&#xff1a;function 函數式&#xff1a;functional 一種編程范式 特點&#xff1a; 把計算視為函數而非指令 純函數式編程&#xff1a;不需要變量&#xff0c;沒有副作用&#xff0c;測試簡單 支持高階函數&#xff0c;代碼簡潔 Python支持的函數式…