Zookeeper_原生API操作(一)
生活随笔
收集整理的這篇文章主要介紹了
Zookeeper_原生API操作(一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
講了zookeeper的簡單的介紹,以及環境搭建,還有zkClient的使用,基本上很簡單,作為HelloWorld,今天繼續往下走,既然已經把簡介和環境搭建完了,然后一會來說說配置,配置也沒有什么說太多的,那我這里有一個配置的文檔,發成PDF的形式發給你了,就是有一個zookeeper的配置文件,配置文件基本上也就這幾個,首先有一個tickTime,就是客戶端和服務器端維持心跳的一個時間間隔,他這個默認也是有一個時間的,你自己看看默認的配置,dataDir就是存儲咱們數據的地方,然后有一個clientPort,客戶端的端口,還有一個initLimit,就是說你的客戶端,你想連我的zookeeper,如果還沒有連上,就認為失敗,總的長度你可以自己去指定,syncLimit,就是leader和follower之間的時間間隔,之前發消息的時間間隔,他不能夠超過=多少時間長度,就掛了,server.0,server.1,server.2,server.3,一共有四個參數需要注意一下,A表示是第幾號服務器,B是IP地址了,C是2888,2888他指的是什么啊,C是這個服務器與集群中的leader服務器交換信息的端口,2888是進行通信的端口號,然后3888,后面的D,表示什么啊,D就表示一個選舉了,一個leader如果掛了話,就需要另外的進行選舉,就是一個新的leader,就是3888,基本上配置很簡單,你可以自己看一下,或者上網找點資料
(一)Zookeeper基礎知識、體系結構、數據模型1 zookeeper是一個類似hdfs的樹形文件結構,zookeeper可以用來保證數據在(zk)集群之間的數據的事務性一致、2 zookeeper有watch事件,是一次性觸發的,當watch監視的數據發生變化時,通知設置了該watch的client,即watcher3 zookeeper有三個角色:Learner,Follower,Observer4 zookeeper應用場景:統一命名服務(Name Service)配置管理(Configuration Management)集群管理(Group Membership)共享鎖(Locks)隊列管理(二) Zookeeper配置(搭建zookeeper服務器集群)1.1 結構:一共三個節點 (zk服務器集群規模不小于3個節點),要求服務器之間系統時間保持一致。1.2 上傳zk 進行解壓: tar zookeeper-3.4.5.tar.gz 重命名: mv zookeeper-3.4.5 zookeeper修改環境變量: vi /etc/profileexport ZOOKEEPER_HOME=/usr/local/zookeeperexport PATH=.:$HADOOP_HOME/bin:$ZOOKEEPER_HOME/bin:$JAVA_HOME/...刷新: source /etc/profile到zookeeper下修改配置文件 cd /usr/local/zookeeper/confmv zoo_sample.cfg zoo.cfg修改conf: vi zoo.cfg 修改兩處(1)dataDir=/usr/local/zookeeper/data (2)最后面添加 server.0=bhz:2888:3888server.1=hadoop1:2888:3888server.2=hadoop2:2888:3888服務器標識配置: 創建文件夾:mkdir data創建文件myid并填寫內容為0:vi myid (內容為服務器標識 : 0)進行復制zookeeper目錄到hadoop01和hadoop02 還有/etc/profile文件把hadoop01、hadoop02中的myid文件里的值修改為1和2 路徑(vi /usr/local/zookeeper/data/myid)啟動zookeeper:路徑:/usr/local/zookeeper/bin執行:zkServer.sh start (注意這里3臺機器都要進行啟動)狀態:zkServer.sh status(在三個節點上檢驗zk的mode,一個leader和倆個follower)1.3 操作zookeeper (shell)zkCli.sh 進入zookeeper客戶端根據提示命令進行操作: 查找:ls / ls /zookeeper創建并賦值:create /bhz hadoop獲取:get /bhz 設值:set /bhz baihezhuo 可以看到zookeeper集群的數據一致性創建節點有倆種類型:短暫(ephemeral) 持久(persistent)(三) zoo.cfg詳解:tickTime: 基本事件單元,以毫秒為單位。這個時間是作為 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每隔 tickTime時間就會發送一個心跳。dataDir: 存儲內存中數據庫快照的位置,顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper 將寫數據的日志文件也保存在這個目錄里。clientPort: 這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。initLimit: 這個配置項是用來配置 Zookeeper 接受客戶端初始化連接時最長能忍受多少個心跳時間間隔數,當已經超過 10 個心跳的時間(也就是 tickTime)長度后 Zookeeper 服務器還沒有收到客戶端的返回信息,那么表明這個客戶端連接失敗。總的時間長度就是 10*2000=20 秒。syncLimit: 這個配置項標識 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 5*2000=10 秒server.A = B:C:D : A表示這個是第幾號服務器,B 是這個服務器的 ip 地址;C 表示的是這個服務器與集群中的 Leader 服務器交換信息的端口;D 表示的是萬一集群中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader
咱們繼續往下走吧,121,122,123,這三個節點啟起來以后,然后整體的zkServer.sh start,回車,三個節點我都要提供zookeeper,然后咱們看一下狀態,然后看一下三個節點的狀態,可能是啟動的并不是那么快,尤其每個節點每臺機器只有一個G的內存,內存到是沒有什么變化,還沒起來,咱們再來一次,這回起來了
有的時候你等待的時間比較長,你下次再status的時候再起來了
這回123是一個leader,然后21和22是一個follower,主從嗎,zookeeper起來了以后,cd到/usr/local下,我們可以通過eclipse來看一下,還是原始默認的情況
然后咱們啟動zookeeper以后呢,之前把shell和環境搭建,剛才其實講了一下配置,在這里其實都已經寫好了
你可以自己去看一看配置文件, vim /usr/local/zookeeper/conf/zoo.cfg,咱們去看一下,他這里都是有默認時間的,tickTime=2000這個2000是2000毫秒,服務器端和客戶端的心跳,還有initLimit=10,都有的,然后還有同步的時間,syncLimit=5,這個更短了,這個是5毫秒,還有其他的,dataDir,clientPort=2181,這個是對外提供服務的一個端口,zookeeper默認的端口就是2181,對外提供的端口,內部提供的端口,一個是做內部通信的,就是121,122,123三者通信就用2888,如果leader掛了的話,就用3888去做,其實這個配置非常簡單
咱們再往下去走,去看
如果我想用JAVA去操作zookeeper,你用什么版本都行,咱們現在用的是3.4.5,其實zookeeper有一套原生的API,然后有一個zkClient,zkClient是在原生API基礎上進行擴展的開源JAVA客戶端,但是原生有一個API,擴展有第三方的API,最好用的是Curator API,一點點說吧,首先簡單看看JAVA代碼吧,我現在用的是3.4.5,直接打開eclipse,咱們這個項目其實已經準備好了
現在我就用zookeeper-3.4.5.jar這一個就夠了,然后包括zkclient的API,curator的API,假如你的項目現在引入了3.4.5,然后怎么去用,我這里有這么多demo,一起來看看,首先看一下base,zookeeper下的base
首先zookeeper實例化這個,這里的構造方法參數肯定都不同,有好多種方式,你會發現這個只是一個比較簡單的API,其實這塊參數還有很多,canBeReadOnly只讀,然后還有些SessionId,還有些sessionPassword,就是做認證的,還有很多東西,有不同的構造方法,提供了4種構造方法,他提供了4種構造方法,參數不同,首先connectString這個就不說了,心跳檢測的超時時間,事件處理器,canBeReadOnly當前會話是否只讀,sessionId和sessionPasswd,這塊其實用的不是很多,就是你這個zookeeper需要一個sessionId和password,然后用zookeeper連的時候需要做一個認證,然后可以提供一個重復對話,我就可以用兩個client端進行操作,兩個client同時可以去登,保證他們兩個操作的數據是可以共享的,怎么理解呢,就是兩個客戶端共享一個session,他們兩個操作是共享的,反正他也提供了這個寫法了,我一般用的比較少,然后zookeeper客戶端和服務端會話的建立是一個異步的過程,我們的程序在處理連接的時候,可能是立即返回,連接成功就是咱們看到的那個,synchronized這個狀態的時候,才算是真正的連接成功,所以因為異步的創建會話的問題,咱們就得使用CountDownLatch一個協調了,就是剛才說的,然后繼續往下看,創建節點一般是znode,這個方法就是非常簡單,create,他提供了兩個API,同步創建,還有一種是異步創建,其實這個API我只是想簡單講一下,我不想講的太深入,你工作中一般不會用到這套API,不會用到zkClient,都會用到curator,因為太難用了,這套API
咱們看一下吧,這是一些參數,直接看代碼比較直觀,臨時節點應該是有一定的時間的,咱們先不說為什么臨時節點創建完了就直接刪除了,咱們一會再看吧,API也沒有說臨時節點創建多久,反正剛才咱們已經看到了,他既然是有返回值,既然run asjava 有返回值,zookeeper一定是三臺機器,三個節點同步的,數據是同步的,兩個follower,一個master,比如說咱們舉個例子,咱們有一個client端C1,再來一個client端C2,咱們知道zk是遵循原子算法的,它是單一視圖的,3個節點上的數據是保持一致的,比如這是根節點/,根節點下有一個/zookeeper節點,然后有一個/testRoot這個節點,然后/testRoot節點下還有個節點就是/children,現在我做的就是臨時的C1,可能開始沒有/children,開始沒有/children這個節點,然后我的這個C1客戶端,我怎么去實現分布式鎖啊,那我就這么去做,當我C1去做一個操作的時候,也就在某一個節點下,在testRoot這個節點下,建立一個children,建立一個臨時的,臨時的節點,然后你其他的數據,總之他創建臨時節點是為了干什么,就是為了占領一把鎖,然后他就去做修改數據了,我去做一些其他的數據庫操作啊,或者做什么操作也好,做完了這個操作以后,然后再把這個children移除,做完操作什么意思,就是zk已經close掉了,close掉就相當于結束了,結束了之后呢,這個C2他想操作,才能操作,我快速把這個問題說完,就是他用一個臨時的節點去做一個值,其實實現起來非常的easy,我寫個偽代碼你們就都懂了,我現在想做一個分布式的操作,咱們這么去理解吧,還是剛才的zookeeper,這邊有3個節點,然后我先做有2個client端,C1變成C2,然后他們想操作同一個數據庫,比如同一個數據,或者兩個數據庫,都無所謂了,就是說現在有一個問題,什么叫分布式呢,你整體的環境中有好幾份應用,就是咱們要開發一個WEB程序,首先我部署到C1上了,然后我又把同樣的程序部署到上了,我生產環境中前端掛一個Nginx,可能我又掛了好幾層Nginx,這個就無所謂了,總之就實現負載均衡了,一會請求他,一會請求他,這個節點其實是我自己的應用,他肯定是一個物理機啊,自己有對應的JDK,有自己的JVM,對應的有自己的JVM,這邊C2也是一樣的,他自己也有對應的JVM,你要理解這個事,然后開發的時候是同一個代碼部署到C1和C2上的,那么問題就來了,如果說我當前有一個用戶,去訪問里面同樣的代碼,我數據庫好多user,我要訪問user,user原先的age年齡,比如25,然后我就要實現在同一個時間點,你不能同一個時間點去減值和加值,如果并發量非常大的話,當然我這里是分布式數據庫,如果是一個數據庫無所謂,如果是兩個數據庫有數據同步的話,第一個節點訪問自己的db,第二個節點也訪問自己的DB,然后兩個DB是MYSQL的主從,或者ORACLE的做雙擊熱備,這個都是可以的,那就相當于我這個DB里面有一張user表,userId比如1,我這個userId也是1,我這個age,你隨便找一個值吧,這個age原先是25,這個數據也是25,用戶肯定是操作界面了,一堆用戶,并發的去訪問Nginx,相當于負載在C1機器上,也負載在C2機器上了,并發就會導致數據不一致的問題,可能就是有一種情況,有n多個請求來對25進行加或者減操作,有可能出現一種情況,就是重復的加,你當前一個請求過來,看到25,對他進行++了,然后他就變成26了,你進行加加的過程中,可能執行邏輯還沒有加加,最后才加加呢,由于是兩個JVM,數據就變成26了,就會有這個問題,可能加重了,要不然減少了,那咱們怎么做啊,是這樣的,我利用這個節點,client端一個請求過來的時候,我先用zookeeper去創建一個臨時的節點,這個臨時節點可以隨意,臨時節點就寫一個ID,這個ID就等于1,那這樣的意思就是什么啊,當C2想對我數據庫user進行操作的時候,C1操作也是,C1想對age加1,C1加1之前先不做其他事,他先去zookeeper上先去create一個node,就是一個臨時的znode,它是1,這邊也是想做一個相同的操作,C2肯定也是去create一個znode,C2也想創建ID為1的,你會發現他創建不了,他就先get一遍,首先是先get,看看zookeeper上有沒有id這個節點,id等于1的這個節點,有的話我就不創建就等待,沒有的話我就create一個id,由于zookeeper支持同一個時間點只能有一個client端,并發再并發只能有一個client端去進行操作,不可能并發同時去修改一個節點id,所以說呢,當我C1操作完了之后,自動會把znode給清空,我清空的時候別人一訪問的時候,id為1的先get一下,一看id為1的沒有,怎么辦,我就create出來,我create一個臨時節點,就相當于一個保護的作用,像一把鎖,你先去查一下zookeeperid等于1的數據別人用不用著,用著我就在這里等著,臨時節點清空了,再去創建一個,加了一把鎖一樣,zookeeper原生的就是這么去實現的,我這么講的你理不理解,能理解這個意思嗎,一個會話創建一個testNode,如果沒有關閉的話,別的會話就創建不了了,這肯定是建不了的,他就是那個機制,差不多他這個分布式鎖就是這么做的
比如我現在有C1,C2兩個客戶端,C1客戶端,這里是C2客戶端,他們想同時操作數據庫里的一張表,兩個都想操作數據庫,一個IP是81,然后C2的IP是82,都要操作同一份user數據,ID等于1,都要操作這個,81和82都要操作同樣的一條數據,會有一個什么情況呢,先去做分布式鎖的時候第一步是這樣的,第一步首先get,比如說我這個節點就寫成這樣,get /usr/1,id直接寫成1,或者string類型的字符串, get /usr/stringuuid,這個你自己隨便起,比如這個人的是ID:1001,user下面去掛一個1001,get /usr/1001,在user這個節點下,有一個1001節點,在來一個1002節點,在來一個1003節點,就表示不同的數據,1001的數據全路徑就是/user/1001,這是一個全路徑,它是key,value是一個數組,你自己隨便去取,首先C1想去做并發操作的時候做分布式鎖的時候,他首先第一步是get,get /user/1001, zookeeper的時候看有沒有這個節點,如果沒有的話,那我就進行create,create一個什么啊,create一個Node,`Node是一個臨時節點類型,我就執行我的UPDATE操作了,update我這臺81機器的持久化操作,然后我持久化操作完了之后呢,我現在肯定不是釋放,肯定是81和82進行數據同步,你要保證這兩臺節點的數據相等,里面有一個name屬性,NAME屬性,或者是COUNT,計數器,COUNT=5,我這邊并發一旦大了,COUNT就改成6了,改成6了之后,現在COUNT變成6了,6一定要和82服務器同步,要不然你持久化操作是這種機制,如果同步不成功的話,就返回持久化失敗,拋出異常或者怎么怎么樣了,然后就是把zk這個節點釋放,你自己去想吧,總之加入正常的情況下,C2這個節點也變成6了,假設我最后做完這個事之后,我要調zk.close(),我這個一close的話,當前這個會話就結束了,當前這個會話一結束,臨時節點就已經消失了,其他人如果想訪問1001的話,就會創建一個臨時節點了,C1比如他在執行UPDATE的過程中,C2能去操作這條記錄嗎,你得去看一下,你得去看 get /user/1001返回的是一個路徑還是一個null值,如果他get之后,返回的是一個null空值的話,那怎么辦啊,就表示是有其他的節點在操作的,那你就等著,什么時候那邊完成了,你這邊才能做這個工作,大體上就是這個事,能理解我說的意思吧,這樣的,你持久化節點的話,zookeeper為什么要提供temp節點,臨時的節點呢,主要目的就是這個事,持久化的話效率可能會低一些,臨時節點刪除和新增性能好一點,你說的是什么問題,get不到返回空你就創建,什么是get不到,get不到我肯定就是create了,兩個都get不到,同時創建就拋異常了吧,兩個都get不到,不存在同時創建的問題,你要知道zookeeper的性能是很好的,就是說你要知道,就是這個集群中,同一個時間點只能有一個人去這里找,不可能是一個時間點兩個請求,精確到毫秒級的,如果他get不到的話,那他直接就create了,create之后,會有一個id產生,這邊他去做的時候,他去創建的時候,你最后創建成功了,你要從代碼的角度去講,即使是有網絡的原因,可能情況是這樣的,這邊網絡有點慢,去zookeeper去取的時候,沒有id為1001的節點,結果創建成功了,就是創建的時候,C2在get的時候,發現也沒有這個ID,他也去創建了,他創建可能也需要很長的時間,但是你最后創建成功了,結果肯定只有一個,創建成功了就馬上同步上去了,當你C2節點又再創建的時候,我就發現已經有了,剛才我已經看到了,重復去創建的話,就拋異常了,肯定就拋異常了,拋異常那就好辦了,就證明我這個節點已經存在了,不可能存在同一個時間點存在兩份的情況,如果要是這么說的話,數據庫并發量大的話,內部肯定是需要做原子消息廣播加鎖的,不需要考慮這些問題,不可能同一個時間節點創建兩份數據,基本上如果是這樣的話,那這個zookeeper就沒法用了,即使你兩個client去get的時候有時間差,這個可以理解,但是你最后創建節點的時候,一個先一個后,不可能第一個請求是0.00001秒,他先創建成功了,第二個節點的時間肯定會差一點點,比如晚一點點,0.00002秒,他創建的時候,直接到zookeeper上去創建,之前已經有了一個創建成功了,報異常就回滾,失敗,證明有人去創建了的,能理解我說的意思吧,get的話網絡的延遲,他們兩個不是一個網絡,第一個get的時候發現沒有,第二個get的時候也發現沒有,那我就去創建節點,只能創建一個,再創建一個的時候就拋異常了,這塊怎么去實現分布式鎖,zookeeper內部的原理,簡單介紹一下
package com.learn.zookeeper.base;import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode;
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.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;/*** 找一個就是一個helloworld程式了* 我打開看一下* 基本上就是一個最簡單的配置了* * @author Leon.Sun**/
public class ZookeeperBase {/** zookeeper地址 *//*** 集群是用逗號分隔的* MQ是分號* 這里是逗號分隔的* 當然其實無所謂* 你寫一個就可以了* 這是咱們的連接串*/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";/** session超時時間 *//*** 這里有一個超時時間* 其實你在zoo.cnf* 配置了一堆東西* 其實你在客戶端連的時候你可以自己配* 這個就是一個SESSION超時的時間* client和zookeeper通信保持的時間* 選擇的是5秒就是5000毫秒* 5秒鐘如果還連不上zookeeper* 我就認為超時了* */static final int SESSION_OUTTIME = 2000;//ms /** 信號量,阻塞程序執行,用于等待zookeeper連接成功,發送成功信號 *//*** 這個還有印象嗎* CountDownLatch這個東西* 他能干什么事呢* 它是一個等待* 一個等待的效果* 比如你那里有一個線程* 咱們看一下這個場景你就明白了* 我現在就用到了CountDownLatch* 總之我把這個實例化出來了* 配置的是1* 1個等待就足夠了* * 為什么要在這里加一個這個東西呢* 其實原理很簡單* 因為咱們的程序連zookeeper是一個異步的* 你比如我這里有一個client端* 這個client端就是咱們寫的代碼* 然后咱們在這里new出一個zookeeper實例* zk實例我new出來以后* 我就回調watcher* 回調watcher他的代碼會一直玩下走* 走到new Watcher()的時候* 他去做了一個真正的connect* 就是我代碼會一直往下走的* 我連接我zookeeper集群是異步的* 可能我連這個花1,2秒* 連的時候稍微有點長* 我的代碼就直接往下走了* zookeeper實例還沒有真正創建好了* 我連接可能還沒有連接好* 這個代碼已經執行其它代碼了* 比如我要create一個節點* 創建一個節點* 那就不行了* 因為你這個zk實例還沒有真正的連接上* 以后肯定是通過一個zk來create一個node* 這個zk如果沒有連接上的時候* 就會發生報空指針異常* 本身這對象啥也沒有* 你點create肯定會報異常* 會有這個問題* 所以我現在就用這種方式去解決了* * */static final CountDownLatch connectedSemaphore = new CountDownLatch(1);/*** 看一下主函數main* * @param args* @throws Exception*/public static void main(String[] args) throws Exception{/*** 你在這里看一下zk* org.apache.zookeeper.ZooKeeper* 現在用的是apache的zookeeper* 是我引入的zookeeper-3.4.5這個包* 這個類就相當于client端實例了* 實例化new一個就足夠了* 傳遞的什么東西呢* 幾個參數* ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) * connectString連接串* 第二個是int類型的sessionTimeout* 就是session超時的時間* 第三個東西叫做Watcher* 發現這個是新接觸的名詞* 他就相當于一個觀察者* 最開始介紹角色的時候* zookeeper這個環境中一共有三種角色* 第一個就是leader* 然后是follower* 這個就不用說了* 第三個就是Observer* Observer是一個特殊的follower* 你也可以把Observer當做一個Watcher* 可以理解為觀察者* 其實就是咱們的client端* 然后他需要一個Watcher* 我就把它實例化出來* new一個Watcher* 它是一個接口* 你把它實例化* 要重新寫一個方法* 就是process方法* 那Watcher new出來的時候你會發現* override一個process方法*/ZooKeeper zk = new ZooKeeper(CONNECT_ADDR, SESSION_OUTTIME, new Watcher(){/*** 里面傳遞一個參數* 一個WatchedEvent* 監控的事件*/@Overridepublic void process(WatchedEvent event) {/*** 下面有一個KeeperState* 用event.getState能獲得KeeperState* 獲得keeperState* 獲取事件的狀態* * 通過event get這個狀態* */KeeperState keeperState = event.getState();/*** event能夠getState* 也能getType* 事件的類型和時間的狀態* 獲取事件的類型*/EventType eventType = event.getType();//如果是建立連接/*** 建立連接這個代碼都是很固定的* 事件都有什么狀態啊* KeeperState.SyncConnected就是連接成功的狀態* 看一下有什么狀態* 有這么多種狀態吧* Disconnected連接失敗* Expired過期* NoSyncConnected沒有連接上* UnKnow也是連接失敗的* 等等一些狀態吧* 這個事件的狀態* SyncConnected就是連接成功的狀態* KeeperState.SyncConnected這個是一個值* 這個值是一個死的* 就是連接成功比如OK* * 如果這個狀態和keeperState想等的話* 那就表示連接成功了*/if(KeeperState.SyncConnected == keeperState){/*** 連接成功我再做* 再做一次判斷* EventType事件的類型* 如果是None是連接開始* 剛連接成功是啥事件也沒有* 所以就是None* 如果None就等于getType的話* 那就表示連接成功* 然后這里面再看一眼* 他有好多種事件的類型* 事件的類型和狀態是兩碼事* 一會詳細去說* 事件類型有好多* NodeChildChanged我子節點發生變更* 還有NodeCreated* 還有NodeDataChanged數據變化* NodeDeleted* None什么也沒做* 他里面提供了5種狀態* 剛連接的時候是啥也沒干* None這種狀態* 那就表示連接成功了* 連接成功了做什么事了* */if(EventType.None == eventType){/*** 假如你要模擬連接時間很長*/try {/*** 我等待2秒* 然后再countDown*/System.out.println("開始連接.....");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}/*** 然后咱們的zk已經建立連接了* * 什么時候zk真正連接成功了* 這句話打印了* 滿足EventType.SyncConnected == eventType這個條件和* KeeperState.SyncConnected == keeperState這個條件了* SyncConnected和SyncConnected我就打印這句話* 把countDown去放行* 然后繼續往下走* 就是這個機制* 能理解我說的意思嗎* 想一想是不是這么回事* 差不多就是這樣的* 這是最原始最古老的寫法* 用的是原生的API* 只有這種方式* * 然后他才執行* 咱們試一下吧* * 現在是他先執行* 然后這邊才這么去做* * 這個代碼是并行的* 這個代碼一放行* 這個代碼就進行往下走* */System.out.println("zk 建立連接");//如果建立連接成功,則發送信號量,讓后續阻塞程序向下執行/*** 我做了一件事情* connectedSemaphore.countDown()* 繼續往下走* * 我這里countDown了* * 你要理解countDown到底是什么含義就夠了* */connectedSemaphore.countDown();// try {
// /**
// * 我在這里sleep2秒
// * 基本上是這樣的
// * 他在連的時候等3秒
// * 3秒之后咱們來看一下
// * 它會發生什么情況
// * 你想想會有什么情況
// * 在這里寫sleep 2秒
// */
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }}}}});//進行阻塞/*** 當代碼執行到這里的時候* 是阻塞的* 程序就不往下走了* 就停在這里*/connectedSemaphore.await();/*** 結果是這個先執行* 因為這里是主線程* 主線程停了其他的就停了* 我主線程要是停了的話* 相當于JAVA代碼全都停止了* 其他線程也就不好使了* 里面的線程都得給我停掉* 能理解這個意思吧* 其實什么意思* 你會發現* */System.out.println("執行啦..");/*** 所以這里sleep一下* sleep時間長就是5秒吧*/Thread.sleep(5000);//創建父節點/*** 這里把包導進來* * 假如我現在執行的代碼是這樣的* create(String path, byte[] data, List<ACL> acl, CreateMode createMode)* create方法里面傳了4個參數* 第一個就是path* path什么意思呢* 你要創建節點節點的路徑是什么* 第二個就是一個byte類型的data* 就對應path的value* 就好像/testRoot這個是key* "testRoot".getBytes()這個是value* 然后后面是一個認證* 一個ACL認證* 其實這個無所謂* 就是OPEN_ACL_UNSAFE* 就是一個安全的東西* 一個靜態的Ids* 咱們一般都選擇這項* 其實還有其他的* 這個你不用擔心* 一般來說都會選擇OPEN_ACL_UNSAFE* 然后還有一個CreateMode* 你創建節點的模式是什么* 創建模式有很多種* 有4種* 首先我創建的是PERSISTENT* 持久化的* 有4種方式* 持久化的普通節點* 還有持久化的順序節點* PERSISTENT SEQUENTIAL* 還有一個臨時節點* EPHEMERAL* 還有臨時的順序節點* 反正就是這4種方式* 提供給創建人員* 我現在使用的是持久化方式的* 然后我去做這種事情* * 咱們看一下API行不行* 咱們直接登錄zkCli.sh就可以了* 然后ls /* 目前根節點下只有一個zookeeper* 我先做是要在根節點下創建一個testRoot* 建立完連接以后呢* 也沒有返回值* String org.apache.zookeeper.ZooKeeper.create()* 有一個String* 應該是節點的信息吧* 現在我有一個問題產生了* 剛才其實我已經創建完節點了* 我可以看一下* ls /* 下面一定是有一個testRoot這個節點的* [zookeeper, testRoot]* 我要是想獲得就使用get /testRoot* 我們能取得testRoot的值testRoot* 也叫testRoot* 就是我再去create一次* 我現在再去創建一次* 同樣的節點/testRoot* 值發生變化"testRoot11"* 現在能創建還是不能創建啊* 你想一想能不能創建* 就是這個節點已經有了* 我現在還想創建還能不能創建* 你想一想猜一猜* KeeperException$NodeExistsException: KeeperErrorCode = NodeExists for /testRoot* NodeExists有了一個節點已經重復了* 所以有節點就不能創建了* 這樣的話有節點就不能創建了* 咱們就刪掉* delete /testRoot* 咱們再次去創建一下* 這種PERSISTENT是持久化的方式* 返回的內容你也看到了* 就是/testRoot* 這就是創建節點* 然后這個內存就變成了testRoot11* 也可以看看* 咱們get /testRoot* 變成testRoot11這個值了* 當前testRoot已經有這個節點了* */
// String ret = zk.create("/testRoot", "testRoot11".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// System.out.println(ret);//創建子節點/*** 然后我想創建一個子節點該怎么去寫啊* 你必須要這么去寫* /testRoot/children* 你必須寫testRoot下面的children* 就是這個children* 然后還有一個問題就是說* 咱們先看這個創建子節點吧* 就是在/testRoot下面再加一個* 寫法就是這樣的* 然后整體的key的value值就是"children data".getBytes()這個* 然后還是使用OPEN_ACL_UNSAFE這種方式* 然后EPHEMERAL這塊注意* 這是一個臨時節點* 臨時節點我記得是有一個時間的* 他就會被清空* 但是我忘了臨時節點是多長時間了* 你可以百度一下查一下* 應該默認是一分鐘還是多久我忘了* ls /testRoot* []* String org.apache.zookeeper.ZooKeeper.create* 返回一個String* 這個是一個臨時的創建節點* 在testRoot下創建一個臨時節點* */
// zk.create("/testRoot/children", "children data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);String ret = zk.create("/testRoot/children", "children data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);/*** /testRoot/children* 其實創建成功了* 因為你是臨時節點* 直接就清空了* 時間也太短了* 直接過長我就忘記了* 反正剛才咱們已經看到了,他既然是有返回值,既然run as 有返回值* 這個節點馬上又被刪除掉了* 他就是創建完了就直接停了* 我想起來了* 是這樣的* 本次會話有效* 下次會話就沒效了* */System.out.println(ret);/*** 咱們在這里sleep10秒* 就是暫停10秒鐘* 這樣去看就能看到效果了* 這個children就一直還在* 然后你等我這個程序停了以后* 我這個child就沒了* 也就是說這個臨時節點啊* 保持這個zk本次會話有效* 臨時會話本次有效* 他可以去做一個什么事啊* 好多人去那他做一個分布式鎖啊* zookeeper去做一個分布式鎖是為一個臨時節點去創建的* 但是這個就有點底層了* 簡單給大家就解釋一下吧* 它是怎么去做的呢* 是這樣的* * */Thread.sleep(10000);/*** 比如我現在有C1,C2兩個客戶端* C1客戶端*//*** 這里是C2客戶端* 他們想同時操作數據庫里的一張表*///獲取節點洗信息
// byte[] data = zk.getData("/testRoot", false, null);
// System.out.println(new String(data));
// System.out.println(zk.getChildren("/testRoot", false));//修改節點的值
// zk.setData("/testRoot", "modify data root".getBytes(), -1);
// byte[] data = zk.getData("/testRoot", false, null);
// System.out.println(new String(data)); //判斷節點是否存在
// System.out.println(zk.exists("/testRoot/children", false));//刪除節點
// zk.delete("/testRoot/children", -1);
// System.out.println(zk.exists("/testRoot/children", false));/*** 做完了之后我就會去做zk的close* 你建立完連接之后呢要關閉*/zk.close();}}
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的Zookeeper_原生API操作(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Zookeeper_环境搭建及客户端使用
- 下一篇: Zookeeper_原生API操作(二)