回顧下zk應用場景:算法
服務註冊與發現負載均衡
再來看看zk在服務註冊與發現中的應用:dom
代碼實現邏輯:分佈式
服務註冊:ide
public class ServiceRegister { private static final String BASE_SERVICES = "/services"; private static final String SERVICE_NAME="/products"; public static void register(String address,int port) { try { ZooKeeper zooKeeper = new ZooKeeper("localhost:2181",5000,(watchedEvent)->{}); Stat exists = zooKeeper.exists(BASE_SERVICES + SERVICE_NAME, false); if(exists==null) { zooKeeper.create(BASE_SERVICES + SERVICE_NAME,"".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } String server_path = address+":"+port; //建立的臨時的有序節點 //臨時的話斷開鏈接了能夠監聽到,有序節點建立表明每個節點不然相同節點名稱沒法建立 zooKeeper.create(BASE_SERVICES + SERVICE_NAME+"/child",server_path.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println("產品服務註冊成功"); } catch (Exception e) { e.printStackTrace(); } } }
發現服務:spa
public class InitListener implements ServletContextListener { private static final String BASE_SERVICES = "/services"; private static final String SERVICE_NAME="/products"; private ZooKeeper zooKeeper; @Override public void contextInitialized(ServletContextEvent sce) { try { zooKeeper = new ZooKeeper("localhost:2181",5000,(watchedEvent)->{ if(watchedEvent.getType() == Watcher.Event.EventType.NodeChildrenChanged && watchedEvent.getPath().equals(BASE_SERVICES+SERVICE_NAME)) { updateServiceList(); } }); updateServiceList(); } catch (Exception e) { e.printStackTrace(); } } private void updateServiceList() { try{ List<String> children = zooKeeper.getChildren(BASE_SERVICES + SERVICE_NAME, true); List<String> newServerList = new ArrayList<String>(); for(String subNode:children) { byte[] data = zooKeeper.getData(BASE_SERVICES + SERVICE_NAME + "/" + subNode, false, null); String host = new String(data, "utf-8"); System.out.println("host:"+host); newServerList.add(host); } //保存註冊服務的ip端口信息,以供遠程rpc調用 LoadBalance.SERVICE_LIST = newServerList; }catch (Exception e) { e.printStackTrace(); } } } public abstract class LoadBalance { public volatile static List<String> SERVICE_LIST; public abstract String choseServiceHost(); } /** * 隨機負載均衡算法 */ public class RamdomLoadBalance extends LoadBalance { @Override public String choseServiceHost() { String result = ""; if(!CollectionUtils.isEmpty(SERVICE_LIST)) { int index = new Random().nextInt(SERVICE_LIST.size()); result = SERVICE_LIST.get(index); } return result ; } }
再講講幾個關鍵點
1.註冊服務的時候須要建立臨時節點,斷開鏈接的時候也就是服務端掛了後節點刪除可監聽到
2.註冊服務的時候建立的是有序節點,通常來講相同服務都是有幾臺機器的,建立順序節點可區分多臺機器的服務
3.發現服務的一端監聽服務節點的子節點,有子節點被刪除了或者有新子節點建立即從新發現服務可用的機器code
dubbo中基於zk的服務註冊與發現也是這個原理server