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~本文到此結束。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM