zoukankan      html  css  js  c++  java
  • zookeeper实现动态感知服务器上下线

      在实际的生产环境中我们一般都是集群环境部署的,同一个程序我们会部署在相同的几台服务器中,这时我们可以通过负载均衡服务器去调度,但是我们并不能很快速的获知哪台服务器挂掉了,这时我们就可以使用zookeeper来解决这个问题。

    zookeeper的动态感知

      动态感知其实利用的就是zookeeper的watch功能,我们先来看下常规的负载均衡服务器的结构
    在这里插入图片描述
    再来看下我们用zookeeper实现的结构
    在这里插入图片描述

    文字描述:

    1.感知上线

      当服务器启动的时候通过程序知道后会同时在zookeeper的servers节点下创建一个新的短暂有序节点来存储当前服务器的信息。客户端通过对servers节点的watch可以立马知道有新的服务器上线了

    2.感知下线

      当我们有个服务器下线后,对应的servers下的短暂有序节点会被删除,此时watch servers节点的客户端也能立马知道哪个服务器下线了,能够及时将访问列表中对应的服务器信息移除,从而实现及时感知服务器的变化。

    代码实现

    服务器端代码

    package com.dpb.dynamic;
    
    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.ZooDefs.Ids;
    import org.apache.zookeeper.ZooKeeper;
    
    /**
     * 服务器端代码
     * @author dengp
     *
     */
    public class DistributedServer {
    
    	private static final String connectString = "192.168.88.121:2181,192.168.88.122:2181,192.168.88.123:2181";
    	private static final int sessionTimeout = 2000;
    	private static final String parentNode = "/servers";
    
    	private ZooKeeper zk = null;
    
    	/**
    	 * 创建到zk的客户端连接
    	 * 
    	 * @throws Exception
    	 */
    	public void getConnect() throws Exception {
    		zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
    			@Override
    			public void process(WatchedEvent event) {
    				// 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
    				System.out.println(event.getType() + "---" + event.getPath());
    				try {
    					zk.getChildren("/", true);
    				} catch (Exception e) {
    				}
    			}
    		});
    
    	}
    
    	/**
    	 * 向zk集群注册服务器信息
    	 * 
    	 * @param hostname
    	 * @throws Exception
    	 */
    	public void registerServer(String hostname) throws Exception {
    
    		String create = zk.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
    		System.out.println(hostname + "is online.." + create);
    
    	}
    
    	/**
    	 * 业务功能
    	 * 
    	 * @throws InterruptedException
    	 */
    	public void handleBussiness(String hostname) throws InterruptedException {
    		System.out.println(hostname + "start working.....");
    		Thread.sleep(Long.MAX_VALUE);
    	}
    
    	public static void main(String[] args) throws Exception {
    
    		// 获取zk连接
    		DistributedServer server = new DistributedServer();
    		server.getConnect();
    
    		// 利用zk连接注册服务器信息
    		server.registerServer(args[0]);
    
    		// 启动业务功能
    		server.handleBussiness(args[0]);
    	}
    }
    

    客户端代码

    package com.dpb.dynamic;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.ZooKeeper;
    /**
     * 客户端:通过zookeeper获取服务器地址
     * @author 波波烤鸭
     *
     */
    public class DistributedClient {
    
    	private static final String connectString = "192.168.88.121:2181,192.168.88.122:2181,192.168.88.123:2181";
    	private static final int sessionTimeout = 2000;
    	private static final String parentNode = "/servers";
    	// 注意:加volatile的意义何在?
    	private volatile List<String> serverList;
    	private ZooKeeper zk = null;
    
    	/**
    	 * 创建到zk的客户端连接
    	 * 
    	 * @throws Exception
    	 */
    	public void getConnect() throws Exception {
    		zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
    			@Override
    			public void process(WatchedEvent event) {
    				// 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
    				try {
    					//重新更新服务器列表,并且注册了监听
    					getServerList();
    				} catch (Exception e) {
    				}
    			}
    		});
    
    	}
    
    	/**
    	 * 获取服务器信息列表
    	 * 
    	 * @throws Exception
    	 */
    	public void getServerList() throws Exception {
    
    		// 获取服务器子节点信息,并且对父节点进行监听
    		List<String> children = zk.getChildren(parentNode, true);
    
    		// 先创建一个局部的list来存服务器信息
    		List<String> servers = new ArrayList<String>();
    		for (String child : children) {
    			// child只是子节点的节点名
    			byte[] data = zk.getData(parentNode + "/" + child, false, null);
    			servers.add(new String(data));
    		}
    		// 把servers赋值给成员变量serverList,已提供给各业务线程使用
    		serverList = servers;
    		
    		//打印服务器列表
    		System.out.println(serverList);
    		
    	}
    
    	/**
    	 * 业务功能
    	 * 
    	 * @throws InterruptedException
    	 */
    	public void handleBussiness() throws InterruptedException {
    		System.out.println("client start working.....");
    		Thread.sleep(Long.MAX_VALUE);
    	}
    	
    	public static void main(String[] args) throws Exception {
    		// 获取zk连接
    		DistributedClient client = new DistributedClient();
    		client.getConnect();
    		// 获取servers的子节点信息(并监听),从中获取服务器信息列表
    		client.getServerList();
    		// 业务线程启动
    		client.handleBussiness();
    	}
    }
    

    测试

    1.在zookeeper中的/下创建一个servers永久节点

    [zk: localhost:2181(CONNECTED) 1] create /servers servers
    Created /servers
    

    1.启动三个服务器

    在这里插入图片描述在这里插入图片描述
    再启动另外两个
    在这里插入图片描述

    3.启动一个客户端

    在这里插入图片描述

    4.关闭一个服务器然后在新开一个服务器观察

    关掉server01后客户端立马打印如下信息
    在这里插入图片描述
    更新了服务器列表,移除了server01
    再开启一个server04服务器查看
    在这里插入图片描述
    客户端获取到了刚刚上线的服务器。
    ok~本文到此结束。

  • 相关阅读:
    json&pickle模块
    Linux BASH 常用命令
    Vmware安装Kali2020
    CentOS7部署Prometheus
    CentOS7部署FreeRadius3.0及WEB管理界面DaloRadius
    Cisco VRRP、TRACK、SLA配置
    Cisco L2TP OVER IPSEC
    Cisco PPTP Server Configration
    华为S5700交换机初始化和配置TELNET远程登录
    华为S5720常用命令
  • 原文地址:https://www.cnblogs.com/dengpengbo/p/10443547.html
Copyright © 2011-2022 走看看