如何實現(xiàn)Zookeeper動態(tài)更新服務(wù)器列表,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的江口網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
zookeeper內(nèi)部就是一個集群,主節(jié)點是選舉出來的,外部看起來就像只有一臺一樣,保存的是一份狀態(tài)數(shù)據(jù)。 做分布式應(yīng)用協(xié)調(diào)的時候,可以降低開發(fā)難度。
具有高可用性,松耦合交互方式。
String create(String path, byte[] data, Listacl, CreateMode createMode) Stat exists(String path, boolean watch) void delete(String path, int version) List getChildren(String path, boolean watch) List getChildren(String path, boolean watch) Stat setData(String path, byte[] data, int version) byte[] getData(String path, boolean watch, Stat stat) void addAuthInfo(String scheme, byte[] auth) Stat setACL(String path, List acl, int version) List getACL(String path, Stat stat)
zookeeper一般來說保管的數(shù)據(jù)不超過1M.主要是保存一些配置信息,主要特點是監(jiān)聽數(shù)據(jù)實時更新。
1、集群管理:規(guī)定編號最小的為master,所以當我們對SERVERS節(jié)點做監(jiān)控的時候,得到服務(wù)器列表,只要所有集群機器邏輯認為最小編號節(jié)點為master,那么master就被選出,而這個master宕機的時候,相應(yīng)的znode會消失,然后新的服務(wù)器列表就被推送到客戶端,然后每個節(jié)點邏輯認為最小編號節(jié)點為master,這樣就做到動態(tài)master選舉。
2、配置的管理:在分布式應(yīng)用環(huán)境中很常見,例如同一個應(yīng)用系統(tǒng)需要多臺 PC Server 運行,但是它們運行的應(yīng)用系統(tǒng)的某些配置項是相同的,如果要修改這些相同的配置項,那么就必須同時修改每臺運行這個應(yīng)用系統(tǒng)的 PC Server,這樣非常麻煩而且容易出錯。 將配置信息保存在 Zookeeper 的某個目錄節(jié)點中,然后將所有需要修改的應(yīng)用機器監(jiān)控配置信息的狀態(tài),一旦配置信息發(fā)生變化,每臺應(yīng)用機器就會收到 Zookeeper 的通知,然后從 Zookeeper 獲取新的配置信息應(yīng)用到系統(tǒng)中。
3、共享鎖:在同一個進程中很容易實現(xiàn),但是在跨進程或者在不同 Server 之間就不好實現(xiàn)了。Zookeeper 卻很容易實現(xiàn)這個功能,實現(xiàn)方式也是需要獲得鎖的 Server 創(chuàng)建一個 EPHEMERAL_SEQUENTIAL 目錄節(jié)點,然后調(diào)用 getChildren方法獲取當前的目錄節(jié)點列表中最小的目錄節(jié)點是不是就是自己創(chuàng)建的目錄節(jié)點,如果正是自己創(chuàng)建的,那么它就獲得了這個鎖,如果不是那么它就調(diào)用 exists(String path, boolean watch) 方法并監(jiān)控 Zookeeper 上目錄節(jié)點列表的變化,一直到自己創(chuàng)建的節(jié)點是列表中最小編號的目錄節(jié)點,從而獲得鎖,釋放鎖很簡單,只要刪除前面它自己所創(chuàng)建的目錄節(jié)點就行了。
4、隊列管理:Zookeeper 可以處理兩種類型的隊列:當一個隊列的成員都聚齊時,這個隊列才可用,否則一直等待所有成員到達,這種是同步隊列;隊列按照 FIFO 方式進行入隊和出隊操作,例如實現(xiàn)生產(chǎn)者和消費者模型
在eclipse中,我們可以導(dǎo)入需要的包,然后對節(jié)點進行增刪改查操作。 當連接的時候可以這樣,這里我是采用了3臺zookeeper來進行操作的。ubuntu1,2,3都分別是主機名
ZooKeeper zk = null; @Before public void init() throws Exception{ zk = new ZooKeeper("ubuntu2:2181,ubuntu1:2181,ubuntu3:2181", 5000, new Watcher() { //監(jiān)聽事件發(fā)生時的回調(diào)方法 @Override public void process(WatchedEvent event) { System.out.println(event.getPath()); System.out.println(event.getType()); } }); }
創(chuàng)建節(jié)點: 這里我是采用創(chuàng)建一個永久節(jié)點,在zookeeper節(jié)點中有臨時節(jié)點和永久節(jié)點之分。在跟目錄下創(chuàng)建一個eclipse節(jié)點,內(nèi)容的編碼格式是utf-8,Ids是指權(quán)限控制,我這里采用的是開放ACL權(quán)限控制。最后需要把流關(guān)閉。
@Test public void testZkNode() throws Exception { String path = zk.create("/eclipse", "指令匯科技".getBytes("utf-8"), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("創(chuàng)建了一個永久節(jié)點: " + path); zk.close(); }
然后是注冊監(jiān)聽器,畢竟zookeeper有一個很重要的功能就是是用來監(jiān)聽整個服務(wù)的狀態(tài)。
@Test public void testGet() throws Exception { //監(jiān)聽器的注冊只能生效一次byte[] data = zk.getData("/eclipse", true, new Stat()); System.out.println(new String(data,"utf-8")); Thread.sleep(Long.MAX_VALUE); }
在main方法中調(diào)用執(zhí)行。
@Test public void testSet() throws UnsupportedEncodingException, KeeperException, InterruptedException{ zk.setData("/eclipse", "誰是英雄".getBytes("utf-8"), -1); zk.close(); }
因為我主要分享的是如何在客戶端上動態(tài)的監(jiān)聽服務(wù)器的上線和離線,所以我們先來寫一個服務(wù)器的進程。
首先我們需要把后面需要的節(jié)點信息定義一下,先去zookeeper的客戶端上面運行一下,創(chuàng)建一個grpnode節(jié)點,以便我們的后續(xù)操作。
private ZooKeeper zk; private String groupNode = "grpnode"; private String subNode = "sub"; // 向zookeeper注冊信息public void connectZK(String name) throws KeeperException, InterruptedException, IOException { zk = new ZooKeeper("ubuntu2:2181,ubuntu1:2181,ubuntu3:2181", 5000, new Watcher() { //監(jiān)聽事件發(fā)生時的回調(diào)方法 @Override public void process(WatchedEvent event) { } }); String path = zk.create("/" + groupNode + "/" + subNode, name.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println("服務(wù)器上線,創(chuàng)建了一個子節(jié)點: " + path); }
接下來就是zookeeper默認的業(yè)務(wù)邏輯的處理,最后在主方法中調(diào)用。當然也可以把這個打成一個jar包放到hadoop上面去運行。
// 業(yè)務(wù)處理邏輯public void handle() throws Exception { Thread.sleep(Long.MAX_VALUE); } public static void main(String[] args) throws Exception { if(args.length==0){ System.err.println("參數(shù)個數(shù)不對,請附加服務(wù)器名作為參數(shù)來啟動....."); System.exit(1); } // 去向zookeeper注冊本服務(wù)器信息AppServer server = new AppServer(); server.connectZK(args[0]); server.handle(); }
服務(wù)器寫好之后,我們就需要一個客戶端來監(jiān)聽這個服務(wù)器的上下線操作了。同樣使用一個zookeeper的監(jiān)聽回調(diào)方法。一旦服務(wù)器發(fā)生變化,這里就可以動態(tài)監(jiān)聽到。主要是監(jiān)聽父子節(jié)點的變化情況。
private volatile Listservers; private ZooKeeper zk; //使用zk的監(jiān)聽器功能觸發(fā)服務(wù)器更新的動作public void connectZK() throws IOException, KeeperException, InterruptedException{ zk = new ZooKeeper("ubuntu2:2181,ubuntu1:2181,ubuntu3:2181", 5000, new Watcher() { //監(jiān)聽事件發(fā)生時的回調(diào)方法 @Override public void process(WatchedEvent event) { if("/grpnode".equals(event.getPath()) && event.getType()==EventType.NodeChildrenChanged ){ //觸發(fā)更新服務(wù)器列表的動作try { updateServerList(); } catch (Exception e) { e.printStackTrace(); } } } }); updateServerList(); }
動態(tài)獲取服務(wù)器列表,這里主要就是監(jiān)聽父子節(jié)點的變化。
//動態(tài)獲取服務(wù)器列表public void updateServerList() throws KeeperException, InterruptedException, UnsupportedEncodingException{ ArrayListserverList=new ArrayList (); //監(jiān)聽子節(jié)點,并且對父節(jié)點注冊監(jiān)聽器List childer=zk.getChildren("/grpnode", true); //遍歷子節(jié)點for(String child:childer){ byte[] data=zk.getData("/grpnode/"+child,false, new Stat()); String server=new String(data,"utf-8"); //將獲取到的服務(wù)器名稱存入list serverList.add(server); } //把暫存的list放到全局的list中servers=serverList; System.out.println("最新的在線服務(wù)器是:"+serverList); }
最后就是我們最熟悉的main方法了
//客戶端的業(yè)務(wù)功能public void handle() throws InterruptedException{ Thread.sleep(Long.MAX_VALUE); } public static void main(String[] args) throws IOException, InterruptedException, KeeperException{ AppClient client=new AppClient(); client.connectZK(); client.handle(); }Zookeeper 作為 Hadoop 項目中的一個子項目,是 Hadoop 集群管理的一個必不可少的模塊,它主要用來控制集群中的數(shù)據(jù),如它管理 Hadoop 集群中的 NameNode,還有 Hbase 中 Master Election、Server 之間狀態(tài)同步等。 Zoopkeeper 提供了一套很好的分布式集群管理的機制,就是它這種基于層次型的目錄樹的數(shù)據(jù)結(jié)構(gòu),并對樹中的節(jié)點進行有效管理,從而可以設(shè)計出多種多樣的分布式的數(shù)據(jù)管理模型
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。