zookeeper【3】服务发现
服务发现:指对集群中的服务上下线做统一管理,每个工作服务器都可以作为数据的发布方,向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息。当工作服务器的基本信息改变时,如服务上下线、服务器的角色或服务范围变更,那么监控服务器可以得到通知并响应这些变化。
实现代码如下:
import com.alibaba.fastjson.JSON;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNoNodeException; /**
* 代表工作服务器
*/
public class WorkServer { private ZkClient zkClient;
// ZooKeeper
private String configPath;
// ZooKeeper集群中servers节点的路径
private String serversPath;
// 当前工作服务器的基本信息
private ServerData serverData;
// 当前工作服务器的配置信息
private ServerConfig serverConfig;
private IZkDataListener dataListener; public WorkServer(String configPath, String serversPath,
ServerData serverData, ZkClient zkClient, ServerConfig initConfig) {
this.zkClient = zkClient;
this.serversPath = serversPath;
this.configPath = configPath;
this.serverConfig = initConfig;
this.serverData = serverData; this.dataListener = new IZkDataListener() { public void handleDataDeleted(String dataPath) throws Exception { } public void handleDataChange(String dataPath, Object data)
throws Exception {
String retJson = new String((byte[])data);
ServerConfig serverConfigLocal = (ServerConfig) JSON.parseObject(retJson,ServerConfig.class);
updateConfig(serverConfigLocal);
System.out.println("new Work server config is:"+serverConfig.toString()); }
}; } // 启动服务器
public void start() {
System.out.println("work server start...");
initRunning();
} // 停止服务器
public void stop() {
System.out.println("work server stop...");
zkClient.unsubscribeDataChanges(configPath, dataListener); // 取消监听config节点
} // 服务器初始化
private void initRunning() {
registMe(); // 注册自己
zkClient.subscribeDataChanges(configPath, dataListener); // 订阅config节点的改变事件
} // 启动时向zookeeper注册自己的注册函数
private void registMe() {
String mePath = serversPath.concat("/").concat(serverData.getAddress()); try {
zkClient.createEphemeral(mePath, JSON.toJSONString(serverData)
.getBytes());
} catch (ZkNoNodeException e) {
zkClient.createPersistent(serversPath, true);
registMe();
}
} // 更新自己的配置信息
private void updateConfig(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
} }
/**
* 调度类
*/
public class SubscribeZkClient { private static final int CLIENT_QTY = 5; // Work Server数量 private static final String ZOOKEEPER_SERVER = "192.168.1.105:2181"; private static final String CONFIG_PATH = "/config";
private static final String COMMAND_PATH = "/command";
private static final String SERVERS_PATH = "/servers"; public static void main(String[] args) throws Exception { List<ZkClient> clients = new ArrayList<ZkClient>();
List<WorkServer> workServers = new ArrayList<WorkServer>();
ManageServer manageServer = null; try { // 创建一个默认的配置
ServerConfig initConfig = new ServerConfig();
initConfig.setDbPwd("123456");
initConfig.setDbUrl("jdbc:mysql://localhost:3306/mydb");
initConfig.setDbUser("root"); // 实例化一个Manage Server
ZkClient clientManage = new ZkClient(ZOOKEEPER_SERVER, 5000, 5000, new BytesPushThroughSerializer());
manageServer = new ManageServer(SERVERS_PATH, COMMAND_PATH,CONFIG_PATH,clientManage,initConfig);
manageServer.start(); // 启动Manage Server // 创建指定个数的工作服务器
for ( int i = 0; i < CLIENT_QTY; ++i ) {
ZkClient client = new ZkClient(ZOOKEEPER_SERVER, 5000, 5000, new BytesPushThroughSerializer());
clients.add(client);
ServerData serverData = new ServerData();
serverData.setId(i);
serverData.setName("WorkServer#"+i);
serverData.setAddress("192.168.1."+i); WorkServer workServer = new WorkServer(CONFIG_PATH, SERVERS_PATH, serverData, client, initConfig);
workServers.add(workServer);
workServer.start(); // 启动工作服务器 } System.out.println("敲回车键退出!\n");
new BufferedReader(new InputStreamReader(System.in)).readLine(); } finally {
System.out.println("Shutting down..."); for ( WorkServer workServer : workServers ) {
try {
workServer.stop();
} catch (Exception e) {
e.printStackTrace();
}
} for ( ZkClient client : clients ) {
try {
client.close();
} catch (Exception e) {
e.printStackTrace();
} }
}
} }
/**
* 服务器基本信息
*/
public class ServerData { private String address;
private Integer id;
private String name; public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "ServerData [address=" + address + ", id=" + id + ", name="
+ name + "]";
} }
/**
* 配置信息
*/
public class ServerConfig { private String dbUrl;
private String dbPwd;
private String dbUser;
public String getDbUrl() {
return dbUrl;
}
public void setDbUrl(String dbUrl) {
this.dbUrl = dbUrl;
}
public String getDbPwd() {
return dbPwd;
}
public void setDbPwd(String dbPwd) {
this.dbPwd = dbPwd;
}
public String getDbUser() {
return dbUser;
}
public void setDbUser(String dbUser) {
this.dbUser = dbUser;
} @Override
public String toString() {
return "ServerConfig [dbUrl=" + dbUrl + ", dbPwd=" + dbPwd
+ ", dbUser=" + dbUser + "]";
} }
import com.alibaba.fastjson.JSON;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.I0Itec.zkclient.exception.ZkNodeExistsException; import java.util.List; public class ManageServer { // zookeeper的servers节点路径
private String serversPath;
// zookeeper的command节点路径
private String commandPath;
// zookeeper的config节点路径
private String configPath;
private ZkClient zkClient;
private ServerConfig config;
// 用于监听servers节点的子节点列表的变化
private IZkChildListener childListener;
// 用于监听command节点数据内容的变化
private IZkDataListener dataListener;
// 工作服务器的列表
private List<String> workServerList; public ManageServer(String serversPath, String commandPath,
String configPath, ZkClient zkClient, ServerConfig config) {
this.serversPath = serversPath;
this.commandPath = commandPath;
this.zkClient = zkClient;
this.config = config;
this.configPath = configPath;
this.childListener = new IZkChildListener() { public void handleChildChange(String parentPath,
List<String> currentChilds) throws Exception {
// TODO Auto-generated method stub
workServerList = currentChilds; // 更新内存中工作服务器列表 System.out.println("work server list changed, new list is ");
execList(); }
};
this.dataListener = new IZkDataListener() { public void handleDataDeleted(String dataPath) throws Exception {
// TODO Auto-generated method stub
// ignore;
} public void handleDataChange(String dataPath, Object data)
throws Exception {
// TODO Auto-generated method stub
String cmd = new String((byte[]) data);
System.out.println("cmd:"+cmd);
exeCmd(cmd); // 执行命令 }
}; } private void initRunning() {
zkClient.subscribeDataChanges(commandPath, dataListener);
zkClient.subscribeChildChanges(serversPath, childListener);
} /*
* 1: list 2: create 3: modify
*/
private void exeCmd(String cmdType) {
if ("list".equals(cmdType)) {
execList(); } else if ("create".equals(cmdType)) {
execCreate();
} else if ("modify".equals(cmdType)) {
execModify();
} else {
System.out.println("error command!" + cmdType);
} } // 列出工作服务器列表
private void execList() {
System.out.println(workServerList.toString());
} // 创建config节点
private void execCreate() {
if (!zkClient.exists(configPath)) {
try {
zkClient.createPersistent(configPath, JSON.toJSONString(config)
.getBytes());
} catch (ZkNodeExistsException e) {
zkClient.writeData(configPath, JSON.toJSONString(config)
.getBytes()); // config节点已经存在,则写入内容就可以了
} catch (ZkNoNodeException e) {
String parentDir = configPath.substring(0,
configPath.lastIndexOf('/'));
zkClient.createPersistent(parentDir, true);
execCreate();
}
}
} // 修改config节点内容
private void execModify() {
// 我们随意修改config的一个属性就可以了
config.setDbUser(config.getDbUser() + "_modify"); try {
zkClient.writeData(configPath, JSON.toJSONString(config).getBytes());
} catch (ZkNoNodeException e) {
execCreate(); // 写入时config节点还未存在,则创建它
}
} // 启动工作服务器
public void start() {
initRunning();
} // 停止工作服务器
public void stop() {
zkClient.unsubscribeChildChanges(serversPath, childListener);
zkClient.unsubscribeDataChanges(commandPath, dataListener);
} }
zookeeper【3】服务发现的更多相关文章
- 阿里巴巴为什么不用 ZooKeeper 做服务发现?
阿里巴巴为什么不用 ZooKeeper 做服务发现? http://jm.taobao.org/2018/06/13/%E5%81%9A%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8 ...
- 【转帖】为什么不要把ZooKeeper用于服务发现
http://www.infoq.com/cn/news/2014/12/zookeeper-service-finding ZooKeeper是Apache基金会下的一个开源的.高可用的分布式应用协 ...
- 为什么不应该使用Zookeeper做服务发现?(转载)
转载自: http://dockone.io/article/78 [编者的话]本文作者通过ZooKeeper与Eureka作为Service发现服务(注:WebServices体系中的UDDI就是个 ...
- 为什么不应该使用ZooKeeper做服务发现
[编者的话]本文作者通过ZooKeeper与Eureka作为Service发现服务(注:WebServices体系中的UDDI就是个发现服务)的优劣对比,分享了Knewton在云计算平台部署服务的经验 ...
- 徒手教你使用zookeeper编写服务发现
zookeeper是一个强一致[不严格]的分布式数据库,由多个节点共同组成一个分布式集群,挂掉任意一个节点,数据库仍然可以正常工作,客户端无感知故障切换.客户端向任意一个节点写入数据,其它节点可以立即 ...
- zookeeper服务发现实战及原理--spring-cloud-zookeeper源码分析
1.为什么要服务发现? 服务实例的网络位置都是动态分配的.由于扩展.失败和升级,服务实例会经常动态改变,因此,客户端代码需要使用更加复杂的服务发现机制. 2.常见的服务发现开源组件 etcd—用于共享 ...
- 服务发现框架选型: Consul、Zookeeper还是etcd ?
背景 本文并不介绍服务发现的基本原理.除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现.想直接查看结论的同学,请直接跳到文末.目前,市面上有非常多的服务发现工具, ...
- 服务发现框架选型,Consul还是Zookeeper还是etcd
背景 本文并不介绍服务发现的基本原理.除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现. 想直接查看结论的同学,请直接跳到文末. 目前,市面上有非常多的服务发现工 ...
- k8s全方位监控-prometheus-配置文件介绍以及基于文件服务发现
1.scrape_configs 参数介绍 # 默认的全局配置 global: scrape_interval: 15s # 采集间隔15s,默认为1min一次 evaluation_interval ...
- 服务发现:Zookeeper vs etcd vs Consul
[编者的话]本文对比了Zookeeper.etcd和Consul三种服务发现工具,探讨了最佳的服务发现解决方案,仅供参考. 如果使用预定义的端口,服务越多,发生冲突的可能性越大,毕竟,不可能有两个服务 ...
随机推荐
- Exif xss
这种XSS出现的状况会特别少. Exif是啥??? 可交换图像文件格式(英语:Exchangeable image file format,官方简称Exif),是专门为数码相机的照片设定的,可以记录数 ...
- pre,html转义,abbr缩写,表格table
<pre></pre>预定义文本标签pre(保留换行和空格) <sdds>对html转义 <abbr title="sddsdsds"&g ...
- 【转】GridView 加载空行并点击编辑每一个单元格
代码 <script runat="server"> protectedvoid Button1_Click(object sender, System.EventAr ...
- jquery记忆笔记
1.javascript需要注意的一些问题: ①不要使用==比较,始终坚持使用===比较. false == 0; // true false === 0; // false ②NaN这个特殊的Num ...
- React-Native 之 常用组件Image使用
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- SQL Case when 的使用方法 (转)
Case具有两种格式.简单Case函数和Case搜索函数. --简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END ...
- qlserver排序规则在全角与半角处理中的应用
--1.查询区分全角与半角字符--测试数据DECLARE @t TABLE(col varchar(10))INSERT @t SELECT 'aa'UNION ALL SELECT 'Aa'UNIO ...
- C++ "multiple definition of .. first defined here"
C++ "multiple definition of .. first defined here" 在C++中,有时候需要在不同文件中使用同一个变量.对于这类变量如果处理不当,很 ...
- Ubuntu 使用命令更新 Ubuntu 系统
我们都知道 Ubuntu 是一款 Linux 系统,是开源的系统,随时都在更新,所以人们都说 Linux 系统要比 Windows 系统安全.那么为了我们的电脑安全,我们如何利用 Ubuntu 命令来 ...
- Alpine里的用户管理命令
注意噢,和普通的linux不一样的. 1, 建立一个指定GID的组: addgroup -g 10001 -S groupA 2, 建立一个指定UID的用户,指定shell, 让它属于指定的用户组. ...