日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Zookeeper_原生API操作(二)

發(fā)布時間:2024/4/13 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Zookeeper_原生API操作(二) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
在有curator這個框架之前的時候,然后zookeeper怎么去實現(xiàn)分布式鎖,就是利用剛才的那種方案,就是可以去實現(xiàn),你會有各種各樣的疑問,你剛才講的設計是得先get一下,你不如直接create,因為創(chuàng)建性能還不是那么高的,其實你有各種各樣的疑問你得去了解他,你要知道怎么做才能快,你要為性能考慮才能那樣去做,之前這塊也說了,我們往上走一走吧,很多介紹的東西,你當時有一個大體的概念,但是沒有一個很詳細的概念,剛才在這里為什么那么去說,就是他的數(shù)據(jù)基本上是存在內(nèi)存中的,就是他的一些視圖模型,單一視圖,都是在內(nèi)存中的,所以說,在JMater百分百讀的場景下,并發(fā)可以達到這個,12到13萬,你想想吧,所以get的性能是很高的,我一個client端,只要網(wǎng)絡沒有太大的問題,沒有延遲的情況下,get一下馬上就能得到反饋,這個效率是非常高的,所以之前我先get一下有沒有,你不能get都不get就直接create,等著那塊就拋異常了,等著報異常就不好,一般我們不那么去做,就是讓性能能更好,都是先去get一下,先去內(nèi)存里去取,看有沒有這條數(shù)據(jù),然后再決定到底要不要create,極少量的情況下會發(fā)生兩個同時get,這個時候創(chuàng)建點肯定有一個先后順序的,肯定是一個成功,一個失敗的,這就是zookeeper怎么去實現(xiàn)分布式這塊

然后再往下看,還是要看這個API,其實倒不如直接講Curator框架,如果不講這些東西,你直接拿去用的話,面試的時候是很吃虧的,zookeeper怎么去實現(xiàn)分布式鎖的,你得講明白是用臨時節(jié)點,為什么啊,因為臨時節(jié)點效率也高,第二點我什么要用get啊,因為zookeeper是有這么一個特性,數(shù)據(jù)是存在內(nèi)存中的,get的性能是非常高的,所以說我這么去做,是有理由有依據(jù)的,然后咱們再去看一下API,這塊要說的一點,咱們是不允許遞歸創(chuàng)建節(jié)點的,你父節(jié)點沒有創(chuàng)建的情況下是不允許創(chuàng)建子節(jié)點的,咱們可以試一試 我們先ls /一下

我把testRoot刪掉, rmr /testRoot

然后ls /,當前只有一個zookeeper節(jié)點,不允許遞歸創(chuàng)建節(jié)點,父節(jié)點不存在的情況下是不允許創(chuàng)建節(jié)點的,它是不允許支持序列化框架的,比如我們能不能做這么一件事,user的key就換一個主鍵ID,value就放一個user對象,或者就一個JAVA對象,這個zookeeper是不支持的,以后它是不支持序列化的,你可以去使用一些第三方的序列化框架,比如Hessian,Kryo序列號框架,就是這些序列號框架,Kryo框架的性能也是非常好的,包括dubbo中也是采用了一種方式,第三個參數(shù)是一個權限節(jié)點,模模糊糊不知道是什么概念,Ids它是一個API,它是一個靜態(tài)的,然后他有一個OPEN_ACL_UNSAFE,開放權限即可,這個表示開放權限,后期有一些參數(shù),基本上我從來沒有關注過,包括很多API封裝的時候,第三方框架就寫死了,一般在權限沒有太高要求的情況下是沒有必要關注的,你就不用費這個事去關注了,相關的問題我們通過網(wǎng)絡,不會考慮太詳細,只不過是他提供的功能是這樣,這個不用關注,然后最后一個是創(chuàng)建節(jié)點類型,有4種類型,有持久化的,有持久化順序的,有個先后順序,當然會有個什么問題,你可能調(diào)一個方法,一個client端C1,現(xiàn)在10個節(jié)點,那你這10個節(jié)點要有順序,可能網(wǎng)絡走到這個時候,第一個創(chuàng)建可能繞了一圈,第二個可能是沒有先后順序的,如果你有順序的話你就可以去看看,你這個zookeeper要做一個隊列,你可以create一個sequential,就是你要那他做一個隊列的一個事,其實很多技術可以提供一個解決方案,就是Redis有一個list類型,它是有一些附加的功能,只不過這種實現(xiàn)起來會比較難,你要抓住最核心的作用是干什么的,然后你輔助的功能,很簡單的情況下你可以去用,我們不用消息隊列,你想實現(xiàn)基于內(nèi)存的,很多問題你自己可以去解決,兩種解決你可以自己去做,包括這個zookeeper也一樣,他想實現(xiàn)一個隊列,他可以去提供這個接口,一般有沒有人這么去做呢,這是我強調(diào)的一個問題,他不僅僅能實現(xiàn)一點,我只是大概提一下,然后往下走,還有一種是異步的方式,節(jié)點也分同步和異步,同步的方式就是我創(chuàng)建完了之后,我發(fā)一個請求到zookeeper上,我這邊得到一個返回值,這是同步的方式,我的代碼肯定是在這一點延遲,創(chuàng)建調(diào)API,同步方式,異步呢,代碼是直接往下走,我又起了一個額外的線程,去監(jiān)聽zookeeper的返回,這是可以去實現(xiàn)的,這里有一個異步方式

package com.learn.zookeeper.base;import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper;/*** 這就是關于zookeeper增刪改查操作* 簡單的講一下* 里面有一些特殊的方法* 每一套API* 無論是exist,delete,還是get* 都有兩套* 一種是同步的方式* 一種是回調(diào)的方式* 然后基本上去操作API呢* 會有一些限制* 比如說不能遞歸的去創(chuàng)建啊* 不能遞歸的去刪除* 去掉getChildren方法的時候* 十六進制JAVA怎么表示來著* 有點不記得了* 用byte[]字節(jié)數(shù)組* get只能取得一層* 你不能把下面的節(jié)點也取得到* 有很多限制* 這是關于咱們zookeeper的API* * @author Leon.Sun**/ public class ZookeeperBase {static final String CONNECT_ADDR = "59.110.138.145:2181"; // static final String CONNECT_ADDR = "192.168.80.88:2181,192.168.80.87:2181,192.168.80.86:2181";static final int SESSION_OUTTIME = 2000;//ms /** 信號量,阻塞程序執(zhí)行,用于等待zookeeper連接成功,發(fā)送成功信號 */static final CountDownLatch connectedSemaphore = new CountDownLatch(1);public static void main(String[] args) throws Exception{ZooKeeper zk = new ZooKeeper(CONNECT_ADDR, SESSION_OUTTIME, new Watcher(){@Overridepublic void process(WatchedEvent event) {KeeperState keeperState = event.getState();EventType eventType = event.getType();//如果是建立連接if(KeeperState.SyncConnected == keeperState){if(EventType.None == eventType){try {System.out.println("開始連接.....");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("zk 建立連接");//如果建立連接成功,則發(fā)送信號量,讓后續(xù)阻塞程序向下執(zhí)行connectedSemaphore.countDown();}}}});//進行阻塞connectedSemaphore.await();System.out.println("執(zhí)行啦..");Thread.sleep(5000);//創(chuàng)建父節(jié)點 // String ret = zk.create("/testRoot", "testRoot11".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); // System.out.println(ret);//創(chuàng)建子節(jié)點/*** 現(xiàn)在我想又一次創(chuàng)建* 肯定是沒有/testRoot這個節(jié)點的* 就像創(chuàng)建/children* 行嗎* 肯定是不行的* 咱們運行一下吧* KeeperException$NoNodeException: KeeperErrorCode = NoNode for /testRoot/children* 就是你沒有父節(jié)點你就想創(chuàng)建子節(jié)點* zookeeper原生的API是不支持的* 怎么去實現(xiàn)的* 你得先判斷一下* 先來個if再來個else* 其實Curator的框架怎么去封裝的呢* 無非就是先if判斷當前* 如果路徑很長的話* 還有個aaa* 還有個ccc* 一層一層的去判斷* 先判斷children他的上一級有沒有* 再判斷ccc他的上一級有沒有* aaa他的上一級有沒有* 其實就是這個意思* 只要他的上一級沒有我就拋一個異常* 然后像Curator框架* 如果不存在我就一層一層的創(chuàng)建* 如果/testRoot這個不存在就創(chuàng)建出來* 如果/aaa這個不存在就創(chuàng)建出來* /ccc這個不存在我還得創(chuàng)建出來* 他有個ifparentexist的方法* 不允許去創(chuàng)建沒有的父節(jié)點的* 咱們把剛才的事說一下* 把剛才的事說一下* 不允許遞歸創(chuàng)建節(jié)點* * */ // String ret = zk.create("/testRoot/aaa/ccc/children", "children data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);/*** 如果你這么去創(chuàng)建是不行的* 咱們ls /一下* 我現(xiàn)在根節(jié)點下只有一個zookeeper* 然后是沒有testRoot的* 創(chuàng)建它會返回一個什么值呢* 它是拋了一個異常* KeeperException$NoNodeException: KeeperErrorCode = NoNode for /testRoot/children* 在原生的zookeeper* 它是不允許你遞歸的去創(chuàng)建節(jié)點的* 以后的Curator框架* 會有一個ifparentexist* 它會幫你把父節(jié)點創(chuàng)建好* 這也是原生API的問題* 其實Curator也是把原生的API進行一個封裝* 無非是在判斷節(jié)點的時候判斷一下他上個節(jié)點是不是存在* 如果不存在就把他創(chuàng)建好* 如果存在的話就創(chuàng)建節(jié)點* 這是第一個問題* 在原生的API中是不允許遞歸創(chuàng)建節(jié)點的*/ // String ret = zk.create("/testRoot/children", "children data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);/*** create其實是有CallBack和Object的* 就是每個方法都提供了兩套API* 一個是正常的創(chuàng)建同步的創(chuàng)建* 還有個是異步的創(chuàng)建* 異步創(chuàng)建效率有點高* 咱們同步的是一個 * 異步的去刪除* 創(chuàng)建成功了* /testRoot* 然后我在下面ls /* 下面就有testRoot這個節(jié)點了* 然后接下來進行delete* 這個Delete操作其實也很簡單* * 這里先注釋* 否則再創(chuàng)建就會報exists節(jié)點已經(jīng)存在* * /testRoot這個創(chuàng)建好了以后* 我再去取的時候就有了* dataVersion = 0* 版本號的標識被改了幾次* update了幾次* * */ // String ret = zk.create("/testRoot", "testRoot11".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); // System.out.println(ret);/*** 現(xiàn)在這樣去做* 我這里delete一個節(jié)點* 其實它這個delte方法也有* zookeeper能存數(shù)據(jù)的版本號* 比如我們?nèi)et /testRoot* dataVersion = 0* 你會發(fā)現(xiàn)這個版本號是0* 這里有很多version* 但是我們就看dataVersion* 第一次是0* 比如我修改一下* set /testRoot 2222* 我再去get的時候發(fā)現(xiàn)dataVersion改變了 * dataVersion = 1* 如果我在改一下* set /testRoot 5555* dataVersion = 2* 我能取到每一個版本號* 對應的你要delete哪一個版本號的數(shù)據(jù)* 你要是寫-1就是全清空* 就是全刪除* 一般我們?nèi)プ鰀elete節(jié)點的話* 現(xiàn)在的testRoot的版本號已經(jīng)到了2了* * 現(xiàn)在我想去刪除* delete一般傳了第二個參數(shù)-1* 4個參數(shù)嗎* 然后這里有一個VoidCallback* Object ctx2可以傳入一個Callback的參數(shù)* 實例化出來VoidCallback這么一個對象* 這個是一個靜態(tài)的* 它是異步的* * */ // zk.delete("/testRoot", -1,new VoidCallback() { // // /** // * 然后你要去重載一個方法是這個processResult // * // * 這就是我之前說的一個callback方法 // * 每一個delete都會存在一個回調(diào) // * // */ // @Override // public void processResult(int rc, String path, Object ctx2) { // /** // * 我休眠1秒鐘 // */ // try { // Thread.sleep(1000); // } catch (InterruptedException e) { // e.printStackTrace(); // } // /** // * 第一個int類型的東西是啥啊 // * 響應碼 // * 如果是0表示回調(diào)成功 // * 如果是-4表示端口連接 // * 如果是-110表示指定節(jié)點存在 // * -112表示會話已經(jīng)過期 // * callback可能成功可能失敗 // * 能有好多個狀態(tài) // */ // System.out.println(rc); // /** // * path表示節(jié)點的參數(shù)路徑是什么 // * // * 第二個參數(shù)是path // * 當前刪除的節(jié)點是什么 // */ // System.out.println(path); // /** // * 然后還有一些東西 // * ctx上下文環(huán)境 // * 還有一個name // * 很多回調(diào)的參數(shù) // * 我現(xiàn)在只取了這三個 // * // */ // System.out.println(ctx2); // } // // /** // * 這個a是一個Object // * 就是傳入任何一個參數(shù) // * 都會回調(diào)到ctx2這里 // * 咱們之前學RocketMQ的事務 // * 事務的callback里面也會有一個參數(shù) // * 其實一個道理 // * 這是一個callback的一個機制 // * -1是跳過版本檢查 // * 如果不是當前的版本就不刪除了 // * 我數(shù)據(jù)庫可能有一份記錄 // * 當前咱兩是不是一個版本號 // * 如果是的話我做一個check // */ // },"a");System.out.println("繼續(xù)執(zhí)行.......");/*** 在這里等待這么長的時間*/ // Thread.sleep(5000);/*** 我現(xiàn)在直接做一個刪除* 成功了以后我們再去get* get /testRoot* Node does not exist: /testRoot* 一般不考慮版本號* 一般用-1* */ // zk.delete("/testRoot", 2);/*** 其實你也不用休眠了*/ // Thread.sleep(10000);//獲取節(jié)點洗信息/*** 接下來看獲得節(jié)點* ZooKeeper.getData(String path, boolean watch, Stat stat) * watch先不用理會* stat狀態(tài)呢也不用理會* 因為如果你要講API的話* 但是不用關注后面兩個參數(shù)* 其實就是想去獲得節(jié)點的value值* value值返回的還是一個data類型* testRoot咱們包裝成一個String* 基本上就是這個操作* 先講簡單的再講復雜的* 咱們create /testRoot 1122* 創(chuàng)建成功以后ls /* 看到testRoot了* 咱們現(xiàn)在執(zhí)行一下看有沒有效果* 后面兩個參數(shù)我們后面會講* 先不用關注這么復雜的東西* * */ // byte[] data = zk.getData("/testRoot", false, null); // /** // * 現(xiàn)在我想獲得一堆怎么辦 // * // */System.out.println(new String(data)); // // /** // * 一堆children我想獲得的話 // * // */System.out.println(zk.getChildren("/testRoot", false)); // // /** // * 他返回的是一個String類型的list // * ZooKeeper.getChildren(String path, boolean watch) // * 第二個參數(shù)是watch // * 總是有一個watch的東西 // * 這個東西其實很煩 // * create /testRoot/a1 1111 // * create /testRoot/a2 2222 // * create /testRoot/a5 2222 // * 現(xiàn)在ls /testRoot下面 // * [a1, a2, a5] // * 你會發(fā)現(xiàn)有三個節(jié)點三個孩子了 // * 他相當于一個父親了 // * 然后我現(xiàn)在getChildren的時候 // * 把孩子都給拿出來了 // * 這是很簡單的 // * 返回的類型已經(jīng)固定了 // * // */ // List<String> list = zk.getChildren("/testRoot", false); // // /** // * 我就去循環(huán)他 // * // */ // for (String path : list) { // /** // * 這個path是一個相對的路徑 // * a1,a2,a3 // * 如果你想取值的話 // * 你得加上前面的父路徑/testRoot // * 然后a1,a2,a3 // * 他取出來的是一個相對的 // * 我就用之前取的方法 // * // * 我這塊就是這樣去做的 // * 我直接循環(huán)path // * 看path有沒有就行了 // * 你會發(fā)現(xiàn)這是沒有的 // * 就是getChildren方法你想做遞歸呢 // * 他是只支持直接子節(jié)點 // * 能理解我說的意思吧 // * 這是肯定的 // * 原生API就是這么去實現(xiàn)的 // * 為什么這么去實現(xiàn)呢 // * 其實也是有他的道理的 // * 這是關于getChildren方法的 // * // * // */ // System.out.println(path); // String realPath = "/testRoot/" + path; // /** // * realPath這個路徑傳進去 // * 得到的結果就是1111,2222,2222這個了 // * 這個應該很簡單 // * 暫時不用去理會這個事 // * 先把這個簡單的API講完 // * 再加一層就不行了 // * 你試一下 // * 我在a1下面還有一層b1 // * a1下面有一個b1 // * create /testRoot/a1/b1 11 // * 咱們可能就是這種情況了 // * 我現(xiàn)在能不能把b1也取出來呢 // * // * // */ // System.out.println(new String(zk.getData(realPath, false, null))); // }/*** 修改節(jié)點其實也很簡單* 修改節(jié)點* testRoot原先叫什么名字咱們看一下* get /testRoot* 原先叫1122* 我想給他改成"modify data root"這個* -1就是不檢查版本號了* 不管你版本號這個問題了* 修改完了再去取* 就變成modify data root這個了* get /testRoot* 數(shù)據(jù)就變成modify data root這個了* 這個就相當于update* * */ // zk.setData("/testRoot", "modify data root".getBytes(), -1); // byte[] data = zk.getData("/testRoot", false, null); // System.out.println(new String(data));//修改節(jié)點的值 // zk.setData("/testRoot", "modify data root".getBytes(), -1); // byte[] data = zk.getData("/testRoot", false, null); // System.out.println(new String(data)); //判斷節(jié)點是否存在/*** exists你可以先判斷節(jié)點是否已經(jīng)存在* 比如a2* 打印一下* 它會返回一個布爾類型* 4127,4127,1558515470535,1558515470535,0,0,0,0,4,0,4127* 這個長的字符串不用理會* 就跟cZxid = 0x101b這個有點像了* 來試一下吧* 每次都一樣* 我不知道行不行* * 如果你給一個a5* */ // System.out.println(zk.exists("/testRoot/a1", false));/*** 如果你給一個a8* 我在運行的話* 返回的就是一個Null* null就證明這個節(jié)點不存在* 如何去判斷是否存在* 現(xiàn)在也把exist這個方法測試OK了* 然后最后還有一個delete* 這個delete就不用說了* 就是想刪除一個節(jié)點* 既然不支持遞歸的創(chuàng)建* * get /testRoot* 我現(xiàn)在查的是a2* 那我還得這么去做* get /testRoot/a2* cZxid = 0x1035* a2是這個值也應該存在* * * */System.out.println(zk.exists("/testRoot/a2", false));long k = 0x1035;System.out.println(k);// 刪除節(jié)點/*** 原生的API只有兩個方法* 基本上你找不到遞歸刪除的方法* * */ // zk.delete("/testRoot/a2", -1);/*** 刪除這個就報異常了* KeeperException$NotEmptyException: KeeperErrorCode = Directory not empty for /testRoot* Directory not empty* 這個Directory不是空的* 下面有孩子你就刪不了了* 既不支持遞歸的創(chuàng)建* 也不支持遞歸的刪除* 能理解這個意思嗎* 這是最基本的API操作* 讓你去了解zookeeper最基本的操作* * */ // zk.delete("/testRoot", -1); // System.out.println(zk.exists("/testRoot/a2", false));zk.close();}}

?

總結

以上是生活随笔為你收集整理的Zookeeper_原生API操作(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。