服务发现:指对集群中的服务上下线做统一管理,每个工作服务器都可以作为数据的发布方,向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息。当工作服务器的基本信息改变时,如服务上下线、服务器的角色或服务范围变更,那么监控服务器可以得到通知并响应这些变化。

实现代码如下:

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】服务发现的更多相关文章

  1. 阿里巴巴为什么不用 ZooKeeper 做服务发现?

    阿里巴巴为什么不用 ZooKeeper 做服务发现? http://jm.taobao.org/2018/06/13/%E5%81%9A%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8 ...

  2. 【转帖】为什么不要把ZooKeeper用于服务发现

    http://www.infoq.com/cn/news/2014/12/zookeeper-service-finding ZooKeeper是Apache基金会下的一个开源的.高可用的分布式应用协 ...

  3. 为什么不应该使用Zookeeper做服务发现?(转载)

    转载自: http://dockone.io/article/78 [编者的话]本文作者通过ZooKeeper与Eureka作为Service发现服务(注:WebServices体系中的UDDI就是个 ...

  4. 为什么不应该使用ZooKeeper做服务发现

    [编者的话]本文作者通过ZooKeeper与Eureka作为Service发现服务(注:WebServices体系中的UDDI就是个发现服务)的优劣对比,分享了Knewton在云计算平台部署服务的经验 ...

  5. 徒手教你使用zookeeper编写服务发现

    zookeeper是一个强一致[不严格]的分布式数据库,由多个节点共同组成一个分布式集群,挂掉任意一个节点,数据库仍然可以正常工作,客户端无感知故障切换.客户端向任意一个节点写入数据,其它节点可以立即 ...

  6. zookeeper服务发现实战及原理--spring-cloud-zookeeper源码分析

    1.为什么要服务发现? 服务实例的网络位置都是动态分配的.由于扩展.失败和升级,服务实例会经常动态改变,因此,客户端代码需要使用更加复杂的服务发现机制. 2.常见的服务发现开源组件 etcd—用于共享 ...

  7. 服务发现框架选型: Consul、Zookeeper还是etcd ?

    背景 本文并不介绍服务发现的基本原理.除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现.想直接查看结论的同学,请直接跳到文末.目前,市面上有非常多的服务发现工具, ...

  8. 服务发现框架选型,Consul还是Zookeeper还是etcd

    背景 本文并不介绍服务发现的基本原理.除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现. 想直接查看结论的同学,请直接跳到文末. 目前,市面上有非常多的服务发现工 ...

  9. k8s全方位监控-prometheus-配置文件介绍以及基于文件服务发现

    1.scrape_configs 参数介绍 # 默认的全局配置 global: scrape_interval: 15s # 采集间隔15s,默认为1min一次 evaluation_interval ...

  10. 服务发现:Zookeeper vs etcd vs Consul

    [编者的话]本文对比了Zookeeper.etcd和Consul三种服务发现工具,探讨了最佳的服务发现解决方案,仅供参考. 如果使用预定义的端口,服务越多,发生冲突的可能性越大,毕竟,不可能有两个服务 ...

随机推荐

  1. 内核定时器的使用(好几个例子add_timer)【转】

    转自:http://blog.csdn.net/jidonghui/article/details/7449546 LINUX内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个 ...

  2. aarch64_c1

    CBFlib-0.9.5.15-3.fc26.aarch64.rpm 2017-02-06 06:55 393K fedora Mirroring Project CBFlib-devel-0.9.5 ...

  3. Flask小demo---代码统计系统

    功能要求: 管理员登录 # 第一天 班级管理 # 第一天 学生管理 # 第一天 学生登录 上传代码(zip文件和.py文件) 查看个人提交记录列表 highchar统计 学生列表上方使用柱状图展示现班 ...

  4. Mac 升级一次,php 就崩溃一次,有味,苹果....

    Mac升级系统macOS Sierra后PHP不编译 Mac下搭建PHP开发环境(Apache+PHP+MySQL+phpMyAdmin),当Mac 从OS 10.11升级至macOS Sierra( ...

  5. windows7+cuda8+cudnn6+python36+tensorflow_gpu1.4配置

    下载文件 cuda8,自行网上下载online的安装包就好了 cudnn6 python36 tensorflow_gpu 下载地址:https://pan.baidu.com/s/1mjwOi5E ...

  6. Bugfree3.0.4 Linux环境安装指南

    一. 安装apache服务器 1. 检查apache服务器是否安装 service httpd status 2. 如提示未被识别的服务,则表明组件未安装,需手动安装 yum install http ...

  7. 分别使用docx4j,jacob将文字与图片插入word中书签位置

    项目中需要将一段文字,与人员的签名(图片)插入到上传的word中,上网查询了一下,有许多种方式可以向word中插入文字,发现docx4j与jacob都为比较常见的解决方案,于是就先使用的docx4j进 ...

  8. Centos之链接命令

    链接命令:ln  (link) ln -s [源文件] [目标文件] 功能描述:生成链接文件 选项: -s 创建软链接 硬链接特征: 1,拥有相同的i节点和存储block块,可以看作是同一个文件: 2 ...

  9. SQL语句添加删除修改字段

    用SQL语句添加删除修改字段1.增加字段     alter table docdsp    add dspcodechar(200)2.删除字段     ALTER TABLE table_NAME ...

  10. 安装mysql-python报错解决办法

    报错: 按照网上的办法,安装mysql-connector-c-6.1.10-winx64.msi和MySQL-python-1.2.3.win-amd64-py2.7 .exe都不行,又源码安装My ...