在講分布式鎖之前渐溶,我們先看看zookeeper的基礎(chǔ)特性辉浦,zookeeper主要是一個文件系統(tǒng)數(shù)據(jù)結(jié)構(gòu),節(jié)點可以分為以下幾類
一茎辐、節(jié)點類型
1.PERSISTENT-持久化目錄節(jié)點
當(dāng)客戶端與zookeeper斷開連接后宪郊,該節(jié)點依然存在掂恕,只要不進(jìn)行手動刪除,他將會永久存在
2.PERSISTENT_SEQUENTIAL-持久化順序編號目錄節(jié)點
和持久化目錄節(jié)點類似弛槐,但是會給該節(jié)點名稱進(jìn)行順序編號
3.EPHEMERAL-臨時目錄節(jié)點
當(dāng)客戶端與zookeeper斷開連接后懊亡,該節(jié)點會被刪除
4.EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節(jié)點
和臨時目錄節(jié)點類似,但是會給該節(jié)點名稱進(jìn)行順序編號
5.Container 節(jié)點(3.5.3 版本新增)
當(dāng)只建立一個Container節(jié)點丐黄,和建立一個持久化目錄節(jié)點是一樣的斋配,但是當(dāng)Container節(jié)點,有子節(jié)點時灌闺,子節(jié)點被刪除完后艰争,該Container節(jié)點會被zookeeper自動清除,時間間隔60s桂对;
6.TTL 節(jié)點
和redis過期緩存有點類似甩卓,默認(rèn)禁用,現(xiàn)在該功能不太穩(wěn)定
創(chuàng)建節(jié)點命令
create [-s] [-e] [-c] [-t ttl] path [data] [acl]
s:順序節(jié)點
e:臨時節(jié)點
c:容器節(jié)點
t:可以給節(jié)點添加過期時間蕉斜,默認(rèn)關(guān)閉
二逾柿、監(jiān)聽機(jī)制
客戶端可以監(jiān)聽自己關(guān)系的節(jié)點,或者目錄節(jié)點宅此,或者目錄下的所有子節(jié)點
當(dāng)客戶端監(jiān)聽的對象發(fā)生刪除或者修改(有子節(jié)點被創(chuàng)建机错,或被刪除)時,會觸發(fā)相應(yīng)的事件通知到客戶端
get -w /path
針對節(jié)點監(jiān)聽父腕;當(dāng)節(jié)點觸發(fā)修改事件時弱匪,會通知到監(jiān)聽的客戶端;一旦事件觸發(fā)璧亮,則監(jiān)聽會被移除萧诫,需要根據(jù)相應(yīng)的業(yè)務(wù)來判斷,是否需要繼續(xù)監(jiān)聽枝嘶;
ls -w /path
對目錄進(jìn)行監(jiān)聽帘饶,當(dāng)該目錄下有子節(jié)點的創(chuàng)建,以及刪除群扶,則會觸發(fā)及刻;監(jiān)聽也是一次性的;
ls -R -w /path
對目錄進(jìn)行遞歸監(jiān)聽竞阐,每個目錄下的監(jiān)聽也是一次性的
三提茁、分布式鎖
了解了上面兩個特性,我們來看下zookeeper分布式鎖是怎么實現(xiàn)的馁菜;我們現(xiàn)在一般用的zookeeper客戶端是Curator,這個里面有公平鎖铃岔,非公平鎖汪疮,讀寫鎖等
1.非公平鎖
創(chuàng)建PERSISTENT(臨時目錄節(jié)點)峭火,創(chuàng)建成功則加鎖成功,其他應(yīng)用創(chuàng)建則會失敗智嚷,然后注冊一個當(dāng)前節(jié)點的監(jiān)聽卖丸,掛起線程;當(dāng)獲取鎖的應(yīng)用釋放鎖時(自己釋放或者當(dāng)前機(jī)器掛掉)盏道,刪除該臨時目錄節(jié)點稍浆,則其他監(jiān)聽的應(yīng)用則會被喚醒,再次嘗試獲取鎖猜嘱,獲取成功的繼續(xù)執(zhí)行衅枫,未獲取到鎖的應(yīng)用,則繼續(xù)監(jiān)聽朗伶,然后掛起弦撩;
2.公平鎖
非公平鎖有個弊端,就是羊群效應(yīng)论皆,當(dāng)節(jié)點被刪除時益楼,所有應(yīng)用都會被喚醒爭搶鎖,會加大服務(wù)器的壓力点晴;公平鎖感凤,在某個目錄下創(chuàng)建EPHEMERAL_SEQUENTIAL(臨時順序編號目錄節(jié)點),當(dāng)創(chuàng)建完成后粒督,獲取當(dāng)前目錄下所以節(jié)點陪竿,判斷自己節(jié)點是否是最小節(jié)點,如果是最小節(jié)點坠陈,則獲取到鎖萨惑,繼續(xù)執(zhí)行;如果不是最小節(jié)點仇矾,則監(jiān)聽上一個節(jié)點庸蔼,當(dāng)上一個節(jié)點被釋放時,再次判斷是否是最小節(jié)點贮匕;如果是姐仅,則繼續(xù)執(zhí)行;如下圖3.讀寫鎖
當(dāng)應(yīng)用存在讀多寫少的場景刻盐,則公平鎖也不適用掏膏,并發(fā)量不高,則需要讀寫鎖敦锌;讀寫鎖馒疹,在鎖目錄下創(chuàng)建EPHEMERAL_SEQUENTIAL(臨時順序編號目錄節(jié)點),創(chuàng)建的節(jié)點都有標(biāo)識乙墙,是讀鎖颖变,還是寫鎖生均;當(dāng)讀鎖創(chuàng)建成功后,會獲取到當(dāng)前所有節(jié)點腥刹,如果是最小節(jié)點或者比當(dāng)前節(jié)點更小的都是讀節(jié)點马胧,則繼續(xù)執(zhí)行,如果比當(dāng)前節(jié)點小的節(jié)點中有寫節(jié)點衔峰,則監(jiān)聽該寫節(jié)點佩脊,掛起當(dāng)前線程,當(dāng)寫節(jié)點鎖被釋放時垫卤,當(dāng)前線程被喚醒威彰,獲取所有節(jié)點,再次判斷葫男;當(dāng)寫鎖創(chuàng)建成功時抱冷,判斷邏輯和公平鎖一樣,只要不是最小節(jié)點梢褐,則監(jiān)聽上一個節(jié)點旺遮,掛起當(dāng)前線程;如下圖:三盈咳、zookeeper鎖避免的問題
加鎖成功時耿眉,出現(xiàn)網(wǎng)絡(luò)波動,客戶端立馬連接上時鱼响,導(dǎo)致客戶端應(yīng)用不知道是否加鎖成功鸣剪;所以在每次加鎖時,會加一個當(dāng)前應(yīng)用生成類型與uuid的前綴丈积,當(dāng)應(yīng)用不知道是否加鎖成功時筐骇,獲取到所以節(jié)點,判斷是否有該前綴的節(jié)點江滨,則知道是否加鎖成功铛纬,如果加鎖失敗,則重新加鎖唬滑;