教育行業(yè)A股IPO第一股(股票代碼 003032)

全國(guó)咨詢/投訴熱線:400-618-4000

排他鎖和共享鎖分別是什么?有什么不同?

更新時(shí)間:2020年10月30日18時(shí)14分 來(lái)源:傳智播客 瀏覽次數(shù):

分布式鎖是控制分布式系統(tǒng)之間同步訪問(wèn)共享資源的一種方式。如果不同的系統(tǒng)或是同一個(gè)系統(tǒng)的不同主機(jī)之間共享了一個(gè)或一組資源,那么訪問(wèn)這些資源的時(shí)候,往往需要通過(guò)一些互斥手段來(lái)防止彼此之間的干擾,以保證一致性,在這種情況下,就需要使用分布式鎖了。

在平時(shí)的實(shí)際項(xiàng)目開(kāi)發(fā)中,我們往往很少會(huì)去在意分布式鎖,而是依賴于關(guān)系型數(shù)據(jù)庫(kù)固有的排他性來(lái)實(shí)現(xiàn)不同進(jìn)程之間的互斥。這確實(shí)是一種非常簡(jiǎn)便且被廣泛使用的分布式鎖實(shí)現(xiàn)方式。然而有一個(gè)不爭(zhēng)的事實(shí)是,目前絕大多數(shù)大型分布式系統(tǒng)的性能瓶頸都集中在數(shù)據(jù)庫(kù)操作上。因此,如果上層業(yè)務(wù)再給數(shù)據(jù)庫(kù)添加一些額外的鎖,例如行鎖、表鎖甚至是繁重的事務(wù)處理,那么就會(huì)讓數(shù)據(jù)庫(kù)更加不堪重負(fù)。

下面我們來(lái)看看使用ZooKeeper如何實(shí)現(xiàn)分布式鎖,這里主要講解排他鎖共享鎖兩類(lèi)分布式鎖。

排他鎖

排他鎖(Exclusive Locks,簡(jiǎn)稱(chēng) X 鎖),又稱(chēng)為寫(xiě)鎖或獨(dú)占鎖,是一種基本的鎖類(lèi)型。如果事務(wù) T1對(duì)數(shù)據(jù)對(duì)象 O1加上了排他鎖,那么在整個(gè)加鎖期間,只允許事務(wù) T1對(duì) O1進(jìn)行讀取和更新操作,其他任何事務(wù)都不能再對(duì)這個(gè)數(shù)據(jù)對(duì)象進(jìn)行任何類(lèi)型的操作——直到T1釋放了排他鎖

從上面講解的排他鎖的基本概念中,我們可以看到,排他鎖的核心是如何保證當(dāng)前有且僅有一個(gè)事務(wù)獲得鎖,并且鎖被釋放后,所有正在等待獲取鎖的事務(wù)都能夠被通知到。

下面我們就來(lái)看看如何借助ZooKeeper實(shí)現(xiàn)排他鎖:

① 定義鎖

在通常的Java開(kāi)發(fā)編程中,有兩種常見(jiàn)的方式可以用來(lái)定義鎖,分別是synchronized機(jī)制和JDK5提供的ReentrantLock。然而,在ZooKeeper中,沒(méi)有類(lèi)似于這樣的API可以直接使用,而是通過(guò) ZooKeeper 上的數(shù)據(jù)節(jié)點(diǎn)來(lái)表示一個(gè)鎖,例如/exclusive_lock/lock節(jié)點(diǎn)就可以被定義為一個(gè)鎖,如圖:

1604046911092_分布式鎖01.jpg

② 獲取鎖

在需要獲取排他鎖時(shí),所有的客戶端都會(huì)試圖通過(guò)調(diào)用 create()接口,在/exclusive_lock節(jié)點(diǎn)下創(chuàng)建臨時(shí)子節(jié)點(diǎn)/exclusive_lock/lock。在前面,我們也介紹了,ZooKeeper 會(huì)保證在所有的客戶端中,最終只有一個(gè)客戶端能夠創(chuàng)建成功,那么就可以認(rèn)為該客戶端獲取了鎖。同時(shí),所有沒(méi)有獲取到鎖的客戶端就需要到/exclusive_lock 節(jié)點(diǎn)上注冊(cè)一個(gè)子節(jié)點(diǎn)變更的Watcher監(jiān)聽(tīng),以便實(shí)時(shí)監(jiān)聽(tīng)到lock節(jié)點(diǎn)的變更情況

③釋放鎖

在“定義鎖”部分,我們已經(jīng)提到,/exclusive_lock/lock 是一個(gè)臨時(shí)節(jié)點(diǎn),因此在以下兩種情況下,都有可能釋放鎖。 · 當(dāng)前獲取鎖的客戶端機(jī)器發(fā)生宕機(jī),那么ZooKeeper上的這個(gè)臨時(shí)節(jié)點(diǎn)就會(huì)被移除。 · 正常執(zhí)行完業(yè)務(wù)邏輯后,客戶端就會(huì)主動(dòng)將自己創(chuàng)建的臨時(shí)節(jié)點(diǎn)刪除。 無(wú)論在什么情況下移除了lock節(jié)點(diǎn),ZooKeeper都會(huì)通知所有在/exclusive_lock節(jié)點(diǎn)上注冊(cè)了子節(jié)點(diǎn)變更Watcher監(jiān)聽(tīng)的客戶端。這些客戶端在接收到通知后,再次重新發(fā)起分布式鎖獲取,即重復(fù)“獲取鎖”過(guò)程。整個(gè)排他鎖的獲取和釋放流程,如下圖:

1604046922535_分布式鎖02.jpg


共享鎖

共享鎖(Shared Locks,簡(jiǎn)稱(chēng)S鎖),又稱(chēng)為讀鎖,同樣是一種基本的鎖類(lèi)型。

如果事務(wù)T1對(duì)數(shù)據(jù)對(duì)象O1加上了共享鎖,那么當(dāng)前事務(wù)只能對(duì)O1進(jìn)行讀取操作,其他事務(wù)也只能對(duì)這個(gè)數(shù)據(jù)對(duì)象加共享鎖——直到該數(shù)據(jù)對(duì)象上的所有共享鎖都被釋放。

共享鎖和排他鎖最根本的區(qū)別在于,加上排他鎖后,數(shù)據(jù)對(duì)象只對(duì)一個(gè)事務(wù)可見(jiàn),而加上共享鎖后,數(shù)據(jù)對(duì)所有事務(wù)都可見(jiàn)。

下面我們就來(lái)看看如何借助ZooKeeper來(lái)實(shí)現(xiàn)共享鎖。

① 定義鎖
和排他鎖一樣,同樣是通過(guò) ZooKeeper 上的數(shù)據(jù)節(jié)點(diǎn)來(lái)表示一個(gè)鎖,是一個(gè)類(lèi)似于“/shared_lock/[Hostname]-請(qǐng)求類(lèi)型-序號(hào)”的臨時(shí)順序節(jié)點(diǎn),例如/shared_lock/host1-R-0000000001,那么,這個(gè)節(jié)點(diǎn)就代表了一個(gè)共享鎖,如圖所示:

1604046935038_分布式鎖03.jpg

② 獲取鎖

在需要獲取共享鎖時(shí),所有客戶端都會(huì)到/shared_lock 這個(gè)節(jié)點(diǎn)下面創(chuàng)建一個(gè)臨時(shí)順序節(jié)點(diǎn),如果當(dāng)前是讀請(qǐng)求,那么就創(chuàng)建例如/shared_lock/host1-R-0000000001的節(jié)點(diǎn);如果是寫(xiě)請(qǐng)求,那么就創(chuàng)建例如/shared_lock/host2-W-0000000002的節(jié)點(diǎn)。

判斷讀寫(xiě)順序

通過(guò)Zookeeper來(lái)確定分布式讀寫(xiě)順序,大致分為四步

(1)創(chuàng)建完節(jié)點(diǎn)后,獲取/shared_lock節(jié)點(diǎn)下所有子節(jié)點(diǎn),并對(duì)該節(jié)點(diǎn)變更注冊(cè)監(jiān)聽(tīng)。

(2)確定自己的節(jié)點(diǎn)序號(hào)在所有子節(jié)點(diǎn)中的順序。

(3)對(duì)于讀請(qǐng)求:若沒(méi)有比自己序號(hào)小的子節(jié)點(diǎn)或所有比自己序號(hào)小的子節(jié)點(diǎn)都是讀請(qǐng)求,那么表明自己已經(jīng)成功獲取到共享鎖,同時(shí)開(kāi)始執(zhí)行讀取邏輯,若有寫(xiě)請(qǐng)求,則需要等待。對(duì)于寫(xiě)請(qǐng)求:若自己不是序號(hào)最小的子節(jié)點(diǎn),那么需要等待。

(4)接收到Watcher通知后,重復(fù)步驟1

③ 釋放鎖,其釋放鎖的流程與獨(dú)占鎖一致。


猜你喜歡:

自旋鎖原理是什么?自旋鎖有什么優(yōu)缺點(diǎn)?

Java無(wú)鎖并發(fā)編程教程 

0 分享到:
和我們?cè)诰€交談!