zookeeper實戰之服務註冊與發現

zookeeper應用場景

回顧下zk應用場景:算法

  1. 數據發佈與訂閱
  2. 服務註冊與發現
  3. 分佈式鎖
  4. 分佈式隊列
  5. master選舉
  6. 配置中心
  7. 命名服務
  8. 負載均衡

zookeeper實現服務註冊與發現

服務註冊與發現負載均衡

clipboard.png


再來看看zk在服務註冊與發現中的應用:dom

clipboard.png


代碼實現邏輯:分佈式

clipboard.png

服務註冊: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

相關文章
相關標籤/搜索