ZooKeeper私人学习笔记
俗話說“好記性不如爛筆頭”,編程的海洋如此的浩大,養(yǎng)成做筆記的習(xí)慣是成功的一步!
此筆記主要是ZooKeeper3.4.9版本的筆記,并且筆記都是博主自己一字一字編寫和記錄,有錯(cuò)誤的地方歡迎大家指正。
一、基礎(chǔ)知識(shí):
1、ZooKeeper是一個(gè)分布式的,開放源碼的分布式應(yīng)用程序協(xié)調(diào)服務(wù),它包含一個(gè)簡單的原語集,分布式應(yīng)用程序可以基于它實(shí)現(xiàn)同步
? 服務(wù),配置維護(hù)和命名服務(wù)等。Zookeeper是hadoop的一個(gè)子項(xiàng)目,由于功能卓越,現(xiàn)已是apache的一個(gè)頂級(jí)子項(xiàng)目,應(yīng)用于各種分布
? 式場景。官方網(wǎng)站:http://zookeeper.apache.org。
??
??
2、在分布式應(yīng)用中,由于工程師不能很好地使用鎖機(jī)制,以及基于消息的協(xié)調(diào)機(jī)制不適合在某些應(yīng)用中使用,因此需要有一種可靠的、
? 可擴(kuò)展的、分布式的、可配置的協(xié)調(diào)機(jī)制來統(tǒng)一系統(tǒng)的狀態(tài),Zookeeper的目的就在于此。Zookeeper的節(jié)點(diǎn)和數(shù)據(jù)操作,都能保證
? 在并發(fā)情況下的同步性和安全性,因此Zookeeper經(jīng)常用于分布式鎖的操作,同時(shí)也用于集群數(shù)據(jù)共享的情形。
??
??
3、Zookeeper是通過的連接是長連接的,通過定時(shí)的發(fā)送心跳來檢測服務(wù)器的有效性,當(dāng)檢測到服務(wù)器故障后,會(huì)直接操作該服務(wù)器
? 在Zookeeper上的節(jié)點(diǎn)狀態(tài),當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí),會(huì)通知對(duì)當(dāng)前節(jié)點(diǎn)進(jìn)行檢測的客戶端(即觀察者模式)。
??
??
??
4、Zookeeper的設(shè)計(jì)特點(diǎn):
(1)最終一致性:client不論連接到哪個(gè)Server,展示給它都是同一個(gè)視圖,這是zookeeper最重要的性能。
(2)可靠性:具有簡單、健壯、良好的性能,如果消息m被到一臺(tái)服務(wù)器接受,那么它將被所有的服務(wù)器接受。
(3)實(shí)時(shí)性:Zookeeper保證客戶端將在一個(gè)時(shí)間間隔范圍內(nèi)獲得服務(wù)器的更新信息,或者服務(wù)器失效的信息。
但由于網(wǎng)絡(luò)延時(shí)等原因,Zookeeper不能保證兩個(gè)客戶端能同時(shí)得到剛更新的數(shù)據(jù),如果需要最新數(shù)據(jù),
應(yīng)該在讀數(shù)據(jù)之前調(diào)用sync()接口。
(4)等待無關(guān)(wait-free):慢的或者失效的client不得干預(yù)快速的client的請(qǐng)求,使得每個(gè)client都能有效的等待。
(5)原子性:更新只能成功或者失敗,沒有中間狀態(tài)。
(6)順序性:包括全局有序和偏序兩種:全局有序是指如果在一臺(tái)服務(wù)器上消息a在消息b前發(fā)布,則在所有Server上消息a
?都將在消息b前被發(fā)布;偏序是指如果一個(gè)消息b在消息a后被同一個(gè)發(fā)送者發(fā)布,a必將排在b前面。
?
?
?
5、Zookeeper集群的master選舉,必須要要超過半數(shù)以上的服務(wù)器同意,故Zookeeper集群的服務(wù)器初始數(shù)量應(yīng)為2n+1,即為奇數(shù)臺(tái)。
例如:
如果有2臺(tái)服務(wù)器A和B,假設(shè)A要選舉為master服務(wù)器,但此時(shí)只有一臺(tái)B服務(wù)器,即使B服務(wù)器同意,也只有1臺(tái)服務(wù)器,
因?yàn)椴粷M足n/2 + 1的數(shù)量,即 1 < 2 沒有超過半數(shù),因此會(huì)出現(xiàn)選舉失敗。
6、Zookeeper的使用場景:
(1)統(tǒng)一命名服務(wù)。
分布式應(yīng)用中,通常需要有一套完整的命名規(guī)則,既能夠產(chǎn)生唯一的名稱又便于人識(shí)別和記住,Name Service 已經(jīng)是?
Zookeeper 內(nèi)置的功能,通過調(diào)用API的create創(chuàng)建子節(jié)點(diǎn)。
(2)配置管理。
配置的管理在分布式應(yīng)用環(huán)境中很常見,例如同一個(gè)應(yīng)用系統(tǒng)需要多臺(tái) PC Server 運(yùn)行,如果要修改這些相同的配置
項(xiàng),那么就必須同時(shí)修改每臺(tái)運(yùn)行這個(gè)應(yīng)用系統(tǒng)的 PC Server。像這樣的配置信息完全可以交給 Zookeeper 來管理,將配
置信息保存在 Zookeeper 的某個(gè)目錄節(jié)點(diǎn)中,然后將所有需要修改的應(yīng)用機(jī)器監(jiān)控配置信息的狀態(tài),一旦配置信息發(fā)生變
化,每臺(tái)應(yīng)用機(jī)器就會(huì)收到 Zookeeper 的通知,然后從 Zookeeper 獲取新的配置信息應(yīng)用到系統(tǒng)中。
(3)集群管理。
它們的實(shí)現(xiàn)方式都是在 Zookeeper 上創(chuàng)建一個(gè) EPHEMERAL 類型的目錄節(jié)點(diǎn),然后每個(gè) Server 在它們創(chuàng)建目錄節(jié)點(diǎn)的
父目錄節(jié)點(diǎn)上調(diào)用 getChildren(String path, boolean watch) 方法并設(shè)置 watch 為 true,由于是 EPHEMERAL 目錄節(jié)點(diǎn),
當(dāng)創(chuàng)建它的 Server 死去,這個(gè)目錄節(jié)點(diǎn)也隨之被刪除,所以 Children 將會(huì)變化,這時(shí) getChildren上的 Watch 將會(huì)被
調(diào)用,所以其它 Server 就知道已經(jīng)有某臺(tái) Server 死去了。新增 Server 也是同樣的原理。
(4)共享鎖。
實(shí)現(xiàn)方式也是需要獲得鎖的 Server 創(chuàng)建一個(gè) EPHEMERAL_SEQUENTIAL 目錄節(jié)點(diǎn),然后調(diào)用 getChildren方法獲取當(dāng)前
的目錄節(jié)點(diǎn)列表中最小的目錄節(jié)點(diǎn)是不是就是自己創(chuàng)建的目錄節(jié)點(diǎn),如果正是自己創(chuàng)建的,那么它就獲得了這個(gè)鎖,如果不
是那么它就調(diào)用 exists(String path, boolean watch) 方法并監(jiān)控 Zookeeper 上目錄節(jié)點(diǎn)列表的變化,一直到自己創(chuàng)建
的節(jié)點(diǎn)是列表中最小編號(hào)的目錄節(jié)點(diǎn),從而獲得鎖,釋放鎖很簡單,只要?jiǎng)h除前面它自己所創(chuàng)建的目錄節(jié)點(diǎn)就行了。
(5)隊(duì)列管理。
形式一:當(dāng)一個(gè)隊(duì)列的成員都聚齊時(shí),這個(gè)隊(duì)列才可用,否則一直等待所有成員到達(dá),這種是同步隊(duì)列。
形式二:隊(duì)列按照 FIFO 方式進(jìn)行入隊(duì)和出隊(duì)操作,例如實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者模型。
?
7、當(dāng)客戶端watch某個(gè)znode節(jié)點(diǎn)的時(shí)候,某個(gè)節(jié)點(diǎn)被改變時(shí)(例如數(shù)據(jù)改變或刪除或子節(jié)點(diǎn)有變化等),Zookeeper會(huì)自動(dòng)通知watch
? 的客戶端,然后清空掉此節(jié)點(diǎn)下所有的watch的客戶端。因此,客戶端向繼續(xù)監(jiān)聽某個(gè)znode節(jié)點(diǎn),則必須重新進(jìn)行監(jiān)視watch此節(jié)點(diǎn)。
??
? 此模式其實(shí)就是觀察者模式,當(dāng)被觀察的對(duì)象發(fā)生改變時(shí),通知觀察者。
??
8、Zookeeper服務(wù)器的使用需要注意的幾個(gè)事項(xiàng):
(1)watch監(jiān)視是一次性的,再次監(jiān)視需要重新設(shè)置監(jiān)視節(jié)點(diǎn)。
(2)如果監(jiān)視znode節(jié)點(diǎn)的客戶端失去連接了,那么znode被改變后客戶端是不會(huì)收到通知的,
即使后面客戶端重新連接了Zookeeper。
?
(3)在刪除znode節(jié)點(diǎn)的時(shí)候,只允許在空子節(jié)點(diǎn)的情況下刪除,如果當(dāng)前節(jié)點(diǎn)下有子節(jié)點(diǎn),那么是不允許刪除的。
(4)Zookeeper有種臨時(shí)節(jié)點(diǎn)Ephemeral節(jié)點(diǎn),在此連接斷開后,就會(huì)被自動(dòng)清除。因此臨時(shí)節(jié)點(diǎn)不允許有子節(jié)點(diǎn)。
(5)Zookeeper的節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)不能大于1M,本身的設(shè)計(jì)就不是用來存儲(chǔ)大數(shù)據(jù),因此需要避免節(jié)點(diǎn)下的數(shù)據(jù)過大。
(6)相同的路徑下,不允許有相同名稱的節(jié)點(diǎn)存在,如果創(chuàng)建相同名字的節(jié)點(diǎn)會(huì)在創(chuàng)建時(shí)報(bào)錯(cuò)。如果基本名稱都一樣的,
可以創(chuàng)建序列節(jié)點(diǎn)Sequence節(jié)點(diǎn),Zookeeper會(huì)自動(dòng)在基本名稱后面添加一個(gè)按順序的數(shù)字標(biāo)識(shí)。
?
?
?
9、每個(gè)znode節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)如下:
czxid:創(chuàng)建此節(jié)點(diǎn)時(shí)的zxid(Zookeeper Transition ID)
The zxid of the change that caused this znode to be created.
mzxid:最后更改此節(jié)點(diǎn)的zxid。
The zxid of the change that last modified this znode.
pzxid:最好更改此節(jié)點(diǎn)或子節(jié)點(diǎn)時(shí)的zxid。
The zxid of the change that last modified children of this znode.
ctime:創(chuàng)建此節(jié)點(diǎn)時(shí)的時(shí)間。
The time in milliseconds from epoch when this znode was created.
mtime:最終修改此節(jié)點(diǎn)的時(shí)間。
The time in milliseconds from epoch when this znode was last modified.
dataVersion:當(dāng)前節(jié)點(diǎn)數(shù)據(jù)版本號(hào),數(shù)據(jù)被修改版本號(hào)就會(huì)自增1。
The number of changes to the data of this znode.
cversion:當(dāng)前節(jié)點(diǎn)下的子節(jié)點(diǎn)被修改時(shí)的版本號(hào),子節(jié)點(diǎn)新增或刪除時(shí)會(huì)自增1。
The number of changes to the children of this znode.
aclVersion:當(dāng)前節(jié)點(diǎn)的ACL(訪問控制列表)被修改時(shí)的版本號(hào),每次修改會(huì)自增1。
The number of changes to the ACL of this znode.
ephemeralOwner:如果當(dāng)前節(jié)點(diǎn)是臨時(shí)節(jié)點(diǎn),則存儲(chǔ)session id,如果不是臨時(shí)節(jié)點(diǎn)則為0.
he session id of the owner of this znode if the znode is an ephemeral node.?
If it is not an ephemeral node, it will be zero.
dataLength:當(dāng)前節(jié)點(diǎn)下保存的數(shù)據(jù)長度。
The length of the data field of this znode.
numChildren:當(dāng)前節(jié)點(diǎn)下的子節(jié)點(diǎn)個(gè)數(shù)。
The number of children of this znode.
?
10、Zookeeper的watch機(jī)制:
(1)服務(wù)端維護(hù)兩個(gè)watch列表,一個(gè)是當(dāng)前節(jié)點(diǎn)與數(shù)據(jù)watch列表,另外一個(gè)是子節(jié)點(diǎn)watch列表。
注意:
當(dāng)前節(jié)點(diǎn)與數(shù)據(jù)watch列表:是當(dāng)節(jié)點(diǎn)改變或者節(jié)點(diǎn)數(shù)據(jù)改變時(shí),都會(huì)觸發(fā)的列表。
子節(jié)點(diǎn)watch列表:是當(dāng)子節(jié)點(diǎn)改變時(shí)觸發(fā),而子節(jié)點(diǎn)的數(shù)據(jù)改變時(shí)是不會(huì)觸發(fā)的。
(2)設(shè)置監(jiān)聽者,即指定監(jiān)聽watch的znod節(jié)點(diǎn)的方式:
getData()和exists()設(shè)置當(dāng)前節(jié)點(diǎn)與數(shù)據(jù)Watch,getChildren()設(shè)置子節(jié)點(diǎn)Watch。
(3)觸發(fā)機(jī)制,即會(huì)觸發(fā)watch的方式:
setData()觸發(fā)內(nèi)容Watch。即觸發(fā)當(dāng)前節(jié)點(diǎn)與數(shù)據(jù)watch列表。
create()觸發(fā)其父節(jié)點(diǎn)的子節(jié)點(diǎn)Watch。子節(jié)點(diǎn)watch列表觸發(fā)。
delete()同時(shí)觸發(fā)父節(jié)點(diǎn)的子節(jié)點(diǎn)Watch和當(dāng)前節(jié)點(diǎn)與數(shù)據(jù)Watch。當(dāng)前節(jié)點(diǎn)與數(shù)據(jù)watch列表和子節(jié)點(diǎn)watch列表都有觸發(fā)。
11、Zookeeper的ACL(訪問控制列表):
(1)ACL的權(quán)限分為五類:
CREATE: 創(chuàng)建權(quán)限,允許在該節(jié)點(diǎn)下創(chuàng)建子節(jié)點(diǎn)。you can create a child node.
READ:讀權(quán)限,允許讀取該節(jié)點(diǎn)數(shù)據(jù)和查詢他的所屬子節(jié)點(diǎn)。 you can get data from a node and list its children.
WRITE: 寫權(quán)限,允許在該節(jié)點(diǎn)下修改data數(shù)據(jù)。you can set data for a node.
DELETE: 刪除權(quán)限,允許刪除他的所屬子節(jié)點(diǎn)。you can delete a child node.
ADMIN: 管理權(quán)限,允許再該節(jié)點(diǎn)下設(shè)置ACL。you can set permissions.
注意:CREATE和DELETE都是他所屬的子節(jié)點(diǎn)進(jìn)行權(quán)限控制的,并不是針對(duì)當(dāng)前節(jié)點(diǎn)。
? ? ?即任何人都可以刪除當(dāng)前節(jié)點(diǎn),如果你知道節(jié)點(diǎn)路徑的話。
(2)ACL的權(quán)限是不遞歸的。例如:假設(shè)給一個(gè)節(jié)點(diǎn)設(shè)置了讀權(quán)限的控制,一個(gè)用戶即使沒有讀取當(dāng)前節(jié)點(diǎn)的權(quán)限,
? 但是如果知道當(dāng)前節(jié)點(diǎn)下的子節(jié)點(diǎn)路徑,依舊可以讀取子節(jié)點(diǎn)的數(shù)據(jù),父節(jié)點(diǎn)的權(quán)限不會(huì)遞歸到子節(jié)點(diǎn)。
??
??
??
(3)ACL的控制策略有如下幾類:
world: 它下面只有一個(gè)id, 叫anyone, world:anyone代表任何人。
auth: 它不需要id, 只要是通過authentication的user都有權(quán)限,也就是說默認(rèn)采用的username:password就是
? ? ?當(dāng)前用戶認(rèn)證使用的用戶名和密碼,如果當(dāng)前用戶沒有認(rèn)證過,使用auth策略會(huì)報(bào)錯(cuò)。
digest: 它對(duì)應(yīng)的id為username:BASE64(SHA1(password)),它需要先通過username:password形式的進(jìn)行認(rèn)證。
ip: 它對(duì)應(yīng)的id為客戶機(jī)的IP地址,設(shè)置的時(shí)候可以設(shè)置一個(gè)ip段,比如ip:192.168.1.0/16, 表示匹配前16個(gè)bit的IP段。
x509: 客戶端使用X500的規(guī)則來認(rèn)證。
提示:比較常用的是digest和auth的形式。
?
?
?
二、安裝部署:
1、Zookeeper是用Java語言實(shí)現(xiàn)的,因此必須要先安裝JDK。
2、Zookeeper單臺(tái)服務(wù)器的安裝(基于Linux系統(tǒng)):
步驟一:解壓zookeeper-3.4.9.tar.gz目錄,執(zhí)行命令 tar -zxvf zookeeper-3.4.9.tar.gz -C /usr/user
步驟二:進(jìn)入加壓后的目錄/usr/user/zookeeper-3.4.9 ,在該目錄下創(chuàng)建data和log目錄用于存放數(shù)據(jù)和日志,
執(zhí)行命令 mkdir data log
步驟三:在當(dāng)前Zookeeper目錄下,進(jìn)入conf目錄進(jìn)行配置。新建zoo.cfg文件(Zookeeper默認(rèn)會(huì)加載此配置),然后輸入如下配置:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/users/zookeeper/data
dataLogDir=/usr/users/zookeeper/log
clientPort=2181
?
步驟四:在當(dāng)前Zookeeper目錄下,進(jìn)入bin目錄。執(zhí)行命令來操作Zookeeper服務(wù)。
sh ?zkServer.sh start #啟動(dòng)Zookeeper服務(wù)
sh ?zkServer.sh stop #停止Zookeeper服務(wù)
sh ?zkServer.sh status #查看Zookeeper服務(wù)的運(yùn)行狀態(tài)。
步驟五:通過Zookeeper自帶的客戶端操作Zookeeper服務(wù)。執(zhí)行命令 ?sh zkCli.sh -server localhost:2181?
如果是連接本地Zookeeper服務(wù),并且使用的是默認(rèn)的2181端口,則可以簡寫 sh zkCli.sh?
3、Zookeeper的集群安裝(基于Linux系統(tǒng)):
因?yàn)閆ookeeper本身就是為集群提供服務(wù)的,在設(shè)計(jì)時(shí)就考慮Zookeeper的集群,因此Zookeeper的集群非常簡單?;趩闻_(tái)服務(wù)器
的安裝后,增加如下步驟:假設(shè)有三臺(tái)服務(wù)器 192.168.1.2:2181、192.168.1.3:2181、192.168.1.4:2181
續(xù)步驟一:在當(dāng)前Zookeeper目錄下,進(jìn)入data目錄,創(chuàng)建myid文件(用于給當(dāng)前Zookeeper服務(wù)器添加id標(biāo)識(shí),范圍為1~255)。
? 此處設(shè)置標(biāo)識(shí)如下(myid只需輸入數(shù)字)
? 192.168.1.2服務(wù)器的id為 1
? 192.168.1.3服務(wù)器的id為 2
? 192.168.1.4服務(wù)器的id為 3
??
??
??
繼步驟二:在conf/zoo.cfg配置文件下,添加如下配置信息:
server.1=192.168.1.2:2888:3888
server.2=192.168.1.3:2888:3888
server.3= 92.168.1.4:2888:3888
#1,2,3分別是每個(gè)服務(wù)器的id,后面是對(duì)應(yīng)的ip地址,2888:3888是可以用于Zookeeper服務(wù)器之間內(nèi)部通信使用的端口。
注意:使用Zookeeper集群時(shí),注意防火墻配置,可能會(huì)引起Zookeeper無法探測到其他服務(wù)器,導(dǎo)致啟動(dòng)失敗。
三、java 連接Zookeeper的使用筆記:
1、java連接Zookeeper的開源框架有三種:
第一種是Zookeeper官方提供的原生java api。
第二種是由datameer的工程師開發(fā)的zkClient,源碼在github上可下載。修復(fù)了原生java api的一些bug和簡化api操作。
第三種是curator框架,也是apache開發(fā)的。curator的api更簡單,更能更強(qiáng)大,是最受歡迎的java版Zookeeper連接框架。
注意:本筆記默認(rèn)是使用官方提供的原生api來連接Zookeeper。
2、zookeeper-3.4.9.jar包是java連接Zookeeper服務(wù)端的原生jar包,依賴于slfj日志門面框架的jar包,需要同時(shí)引入,
? 具體的jar包在lib_jar目錄下。
3、原生api使用了java的非阻塞NIO來連接,并且是開啟新的線程來去連接服務(wù)端的。因此,主線程必須要監(jiān)控連接成功事件,
? 在連接成功后才開始操作Zookeeper,以免拋出異常。
??
? 提示:可以借助JDK并發(fā)庫的CountDownLatch 對(duì)象來實(shí)現(xiàn)主線程的阻塞,直到連接成功。
??
? 代碼示例:
final CountDownLatch countDownLatch = new CountDownLatch(1);
//創(chuàng)建Zookeeper的核心對(duì)象,此對(duì)象在創(chuàng)建時(shí)就開啟新的線程去連接服務(wù)端。
ZooKeeper zk = new ZooKeeper("10.17.2.7:2181", 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
//連接成功的狀態(tài),進(jìn)行通知。
if (event.getType() == EventType.None && event.getState() == KeeperState.SyncConnected) {
countDownLatch.countDown();
}
}
});
//等待連接成功。
countDownLatch.await();
//連接成功,開始執(zhí)行對(duì)zk操作的業(yè)務(wù)邏輯。
System.out.println("ZooKeeper 連接成功!");
??
??
??
??
4、原生api可以定制默認(rèn)的watcher監(jiān)視者,就是在創(chuàng)建核心操作類ZooKeeper的時(shí)候,在構(gòu)造方法中指定默認(rèn)的watcher,
? 此方法的所有api中凡是通過boolean值來指定是否監(jiān)視的,如果為true則都是使用默認(rèn)的watcher進(jìn)行監(jiān)視。如果為false,
? 則不進(jìn)行監(jiān)視。
??
? 例如:zk.getData()、zk.getChildren()等方法。
5、Zookeeper服務(wù)器是支持事務(wù)的,因此java版的原生api也支持事務(wù)的操作。實(shí)例代碼如下:
//創(chuàng)建連接
ZooKeeper zk = new ZooKeeper("10.17.2.7:2181", 3000, null);
//獲得事務(wù)對(duì)象
Transaction ts = zk.transaction();
//通過事務(wù)對(duì)象來操作數(shù)據(jù)。如果是用zk對(duì)象來操作數(shù)據(jù),那么是不在此事務(wù)范圍內(nèi)的。如zk.create()操作是不受事務(wù)影響的。
ts.create("/java/a7", "節(jié)點(diǎn)a".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//必須提交事務(wù),否則數(shù)據(jù)修改無效。
ts.commit();
zk.close();
6、使用Zookeeper獲得分布式鎖的基本思想:
? 先創(chuàng)建好一個(gè)獲得鎖的父節(jié)點(diǎn),然后每個(gè)線程在該父節(jié)點(diǎn)下創(chuàng)建自己的EPHEMERAL_SEQUENTIAL節(jié)點(diǎn)(臨時(shí)隊(duì)列節(jié)點(diǎn)),然后獲取
該父節(jié)點(diǎn)下的所有子節(jié)點(diǎn),使用TreeSet進(jìn)行自然排序,然后獲取首個(gè)元素(即序列最小的元素),判斷最小元素的名稱是否是當(dāng)前
創(chuàng)建的最小元素名稱,如果是則表名當(dāng)前線程獲取了鎖,可以執(zhí)行業(yè)務(wù)邏輯。如果不是,則獲取此元素前面的一個(gè)元素,然后進(jìn)行
watch監(jiān)視,當(dāng)監(jiān)視節(jié)點(diǎn)被刪除或,獲取獲取所有的節(jié)點(diǎn)進(jìn)行判斷,重復(fù)執(zhí)行此邏輯,直到當(dāng)前最小元素為當(dāng)前線程創(chuàng)建的最小元素。
注意:當(dāng)獲取鎖的線程操作完成后,必須刪除當(dāng)前節(jié)點(diǎn),以便讓后續(xù)監(jiān)視者執(zhí)行監(jiān)視邏輯的方法,從而讓監(jiān)視者得到鎖。
??
說明:每個(gè)線程創(chuàng)建的節(jié)點(diǎn)必須是EPHEMERAL_SEQUENTIAL節(jié)點(diǎn)。因?yàn)榕R時(shí)節(jié)點(diǎn)會(huì)在當(dāng)前連接斷開后會(huì)自動(dòng)刪除,這樣可以在當(dāng)前線程
?的客戶端宕機(jī)后,及時(shí)的處理掉他所擁有的節(jié)點(diǎn),避免線程死鎖。同時(shí),創(chuàng)建隊(duì)列類型的節(jié)點(diǎn),在創(chuàng)建時(shí)服務(wù)端會(huì)按創(chuàng)建順序
?在節(jié)點(diǎn)名稱后面加一串序列數(shù)字,可以通過此數(shù)字來確定獲取鎖的節(jié)點(diǎn)是哪個(gè)。
?
?
?
附加:除了使用Zookeeper獲取分布式鎖以外,還可以使用redis來獲取,但Zookeeper獲取分布式鎖更方便。
?redis獲取分布式鎖的基本思想:借助setnx和getset命令來實(shí)現(xiàn)。首先通過setnx存儲(chǔ)一個(gè)時(shí)間戳值,此時(shí)間戳表示鎖的有效
?時(shí)間。如果設(shè)置成功,則表名是獲取鎖,當(dāng)前線程可獲得鎖。如果設(shè)置失敗,則開始每隔一段時(shí)間循環(huán)讀取。使用get讀取當(dāng)
?前key的value值,value值存的是鎖的有效時(shí)間,判斷value值是否小于當(dāng)前時(shí)間,如果是,則說明鎖已經(jīng)失效,則根據(jù)當(dāng)前時(shí)
?間計(jì)算出鎖的有效時(shí)間,然后使用getset方法,更新舊的鎖時(shí)間,如果返回的舊值與之前get讀取的值一致,則說明獲取鎖成
?功。如果不一致,則說明被其他線程先執(zhí)行g(shù)etset操作了,則獲取循環(huán)嘗試獲取鎖。
?
?
?setnx命令:是當(dāng)key不存在時(shí)才會(huì)設(shè)置成功并返回1,否則設(shè)置失敗并返回0。
?getset命令:更新當(dāng)前key的value值,并返回舊的value值,如果當(dāng)前沒有舊值,則返回nil。
?get命令:根據(jù)key讀取value值,如果沒有則返回nil。
/***************************************************************附加**********************************************************/
附加1、使用zkCli.sh 腳本進(jìn)入Zookeeper的客戶端,可以使用的命令有:
[zkshell: 0] help
ZooKeeper host:port cmd args
get path [watch]
ls path [watch]
set path data [version]
delquota [-n|-b] path
quit
printwatches on|off
create path data acl
stat path [watch]
listquota path
history
setAcl path acl
getAcl path
sync path
redo cmdno
addauth scheme auth
delete path [version]
deleteall path
setquota -n|-b val path
??
轉(zhuǎn)載于:https://www.cnblogs.com/catgwj/p/7492824.html
總結(jié)
以上是生活随笔為你收集整理的ZooKeeper私人学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [BZOJ1724][Usaco2006
- 下一篇: 电阻降额