zookeeper实现分布式应用系统服务器上下线动态感知程序、监听机制与守护线程
来源:互联网 发布:淘宝怎样收藏店铺 编辑:程序博客网 时间:2024/06/05 08:36
需求
在分布式系统中存在多个服务器,这些服务器可以动态上下线,而客户端可以连接任意服务器,但是如果连接的服务器突然下线那么客户端需要重新连接其他服务器,这就需要在服务器上下线的时候客户端能感知,获取哪些可以连接的服务器。
解决思路
每次服务器启动的时候去zookeeper上进行注册(注册规则自由指定,比如简单使用/servers/server001 hostname),而客户端上线就获取服务器列表,并对节点进行监听,一旦有服务器下线那么就能监听到事件从而重新获取服务器列表。
程序简单实现
服务器端:
/** * 服务端程序 * @author 12706 * */public class DistributedServer { private static final String connectionString = "192.168.25.127:2181," + "192.168.25.129:2181," + "192.168.25.130:2181"; public static final Integer sessionTimeout = 2000; public static ZooKeeper zkClient = null; /** * 获取zookeeper连接 * @throws Exception */ public void getConnection() throws Exception{ zkClient = new ZooKeeper(connectionString, sessionTimeout, new Watcher(){ //收到事件通知后的回调函数(应该是我们自己的事件处理逻辑) public void process(WatchedEvent event) { System.out.println(event.getType()+","+event.getPath()); try { //为了能一直监听,调用一次注册一次 zkClient.getChildren("/", true); }catch(Exception e){ } }}); } /** * 注册服务器信息 * @param hostname 注册的服务器名 * @throws Exception */ public void registerServer(String hostname) throws Exception{ //创建的是带序号的临时节点 生成的节点像/servers/server000001,/servers/server000002等 //节点数据即为注册的主机名 String path = zkClient.create("/servers"+"/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println(hostname+" --上线了-- "+path); } /** * 服务器注册完后,执行业务逻辑 * @param hostname * @throws IOException */ public void executeBusiness(String hostname) throws IOException{ System.out.println(hostname+"开始工作了!"); System.in.read(); } public static void main(String[] args) throws Exception { //获取zookeeper连接 DistributedServer server = new DistributedServer(); server.getConnection(); //服务器上线,完成注册 Scanner scanner = new Scanner(System.in); System.out.println("输入hostname"); String hostname = scanner.nextLine(); server.registerServer(hostname); //执行业务逻辑 server.executeBusiness(hostname); }}
客户端:
/* * 客户端程序 */public class DistributeClient { private static final String connectionString = "192.168.25.127:2181," + "192.168.25.129:2181," + "192.168.25.130:2181"; public static final Integer sessionTimeout = 2000; public static ZooKeeper zkClient = null; public static final String parentNode = "/servers"; //注意:加volatile的意义何在?使得多线程看到的服务器列表一致而不会拷贝到自己的工作空间 public volatile List<String> serverList = new ArrayList<String>(); /** * 获取zookeeper连接 * @throws Exception */ public void getConnection() throws Exception{ zkClient = new ZooKeeper(connectionString, sessionTimeout, new Watcher(){ //收到事件通知后的回调函数(应该是我们自己的事件处理逻辑) public void process(WatchedEvent event) { System.out.println(event.getType()+","+event.getPath()); try { //重新获取(更新)服务器列表,并进行监听 getServerList(); }catch(Exception e){ } }}); } /** * 获取服务器列表信息,并对父节点进行监听 * @throws Exception */ public void getServerList() throws Exception{ //获取服务器列表,并对父节点进行监听 //getChildren()相对于命令行 ls /znode,对子节点进行监听 List<String> children = zkClient.getChildren(parentNode, true); //创建临时集合,将子节点存入 List<String> childrenList = new ArrayList<String>(); for (String child : children) { byte[] data = zkClient.getData(parentNode+"/"+child, false, null); childrenList.add(new String(data)); } //将临时集合中的节点赋给服务器列表serverList,以便业务线程使用 serverList = childrenList; System.out.println(serverList); } /** * 业务功能 * @throws Exception */ public void executeBusiness() throws Exception{ System.out.println("获取的服务器列表:"+serverList); System.out.println("客户端开始工作了..."); System.in.read(); } public static void main(String[] args) throws Exception { //获取zookeeper连接 DistributeClient client = new DistributeClient(); client.getConnection(); //获取服务器列表 client.getServerList(); //业务功能 client.executeBusiness(); }}
测试
运行三次服务器端程序,输入的hostname分别为mini1,mini2,mini3当成注册了三个服务器
运行客户端程序(可以启动多次,简单起见这里就一次)
关闭其中2个(mini1,mini2)连接zookeeper的客户端(关闭后注册的服务器也就消失了),查看客户端输出
一旦服务器下线了,客户端能监听到并且重新获取服务器列表。
zookeepe的监听机制及守护线程
以上述DistributeServer为例,当启动main线程的时候,获取zkClient的时候,会启动两个线程一个是监听器listener一个是客户端连接connet(与zookeeper进行通信,比如节点的增加删除获取等)。当connect调用getChildren(“/”,true)的时候,服务端(zookeeper集群)会获得客户端的ip与监听的节点,当该节点下的子节点编号的时候,会调用客户端的listener去执行process方法。
上面介绍了zkClient开启了两个线程,那么即使main线程执行结束了,只要上述两个线程有一个没有执行结束(比如监听线程)那么程序就不会介绍,那么对于上述程序为什么还要要使用System.in.read()来使程序不结束呢?原因就是设计的时候那两个线程是设计为守护线程的,一旦主程序结束程序就结束,否则如果业务方法都执行完了程序还没结束是不符合逻辑的,所以上述使用了
System.in.read()。
下面写了两个简单的小测试
public class DaemonTest { public static void main(String[] args) { System.out.println("main线程开始..."); new Thread(new Runnable() { public void run() { while (true) { System.out.println("线程进行中..."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } } }).start();; System.out.println("main线程结束"); }}
只要存在线程不结束,那么程序就不会退出。
但是如果将线程设置为守护线程一旦main线程结束那么程序就结束了
public class DaemonTest2 { public static void main(String[] args) { System.out.println("main线程开始..."); Thread thread = new Thread(new Runnable() { public void run() { while (true) { System.out.println("线程进行中..."); try { Thread.sleep(2000); } catch (InterruptedException e) { } } } }); thread.setDaemon(true); thread.start(); System.out.println("main线程结束"); }}
输出后程序立马就会退出
main线程开始...main线程结束线程进行中...
- zookeeper实现分布式应用系统服务器上下线动态感知程序、监听机制与守护线程
- ZooKeeper分布式应用系统服务器上下线动态感知简单程序
- 【ZooKeeper】分布式系统服务器上下线自动感知程序开发
- 利用zookeeper实现分布式运用服务器上下线的动态感知-简单程序
- 分布式应用系统服务器上下线动态感知程序开发学习笔记
- zookeeper 服务器动态上下线感知
- 通过Zookeeper动态感知服务器上下线[案例]
- 学习笔记:Zookeeper 应用案例(上下线动态感知)
- 动态感知服务器上下线
- zookeeper实时感知到主节点服务器的上下线
- Zookeeper应用:服务端上下线
- Zookeeper实现服务上下线监控服务列表
- 动态上下线datanode节点及副本均衡机制
- 实践:zookeeper如何在客户端上动态的监听服务器的上线和离线的
- 项目day01--<客户上下线时间程序实现>(上)
- 分布式一致性系统的动态替换实现机制
- 项目day02--<客户上下线时间程序实现>(中)
- Zookeeper在大型分布式系统中的应用
- STL:计算集合的并
- Matplotlib 入门(二):画图
- std::common_type用法
- MapKit/地图定位导航(第三篇:后台定位)
- spring boot 第一篇 构建第一个spring boot工程
- zookeeper实现分布式应用系统服务器上下线动态感知程序、监听机制与守护线程
- HTML DOM学习笔记(一)_简介
- coursera Stanford Machine Learning Week5 Ex4机器学习 实验4
- 更改的资料
- 磁芯存储器简介------顺便说说core dump的core是什么含义
- 打印机模拟(彩色篇)
- 【金融财经】金融市场一周简报(2017-09-22)
- PostgreSQL数据库排查脚本规划
- 【LeetCode算法练习(C++)】Integer to Roman