深入淺出探索Java分布式鎖原理
什么是分布式鎖?它能干什么?
相信大家對(duì)于Java提供的synchronized關(guān)鍵字以及Lock鎖都不陌生,在實(shí)際的項(xiàng)目中大家都使用過(guò)。如下圖所示,在同一個(gè)JVM進(jìn)程中,Thread1獲得鎖之后,對(duì)共享資源進(jìn)行操作,其他線程未獲得鎖的線程只能等待Thread1釋放后才能進(jìn)行對(duì)應(yīng)的操作。

但是隨著業(yè)務(wù)的不斷發(fā)展,原先的單體應(yīng)用被拆分為多個(gè)微服務(wù),每個(gè)微服務(wù)又會(huì)部署多個(gè)實(shí)例,于是就形成了當(dāng)下的微服務(wù)架構(gòu)。處理共享資源的請(qǐng)求來(lái)自不同的服務(wù)實(shí)例,也就是在不同的JVM進(jìn)程中。原先的單體服務(wù)中的加鎖方式在分布式場(chǎng)景下不能滿足共享資源的并發(fā)訪問(wèn)要求。因此我們需要一種適用于分布式場(chǎng)景下的共享資源安全的處理機(jī)制,此時(shí)應(yīng)對(duì)這種問(wèn)題的分布式鎖就應(yīng)運(yùn)而生了。
既然JVM進(jìn)程管不到其他服務(wù)實(shí)例的線程,那么可以借助于外部組件能力來(lái)實(shí)現(xiàn)不同服務(wù)實(shí)例對(duì)于共享資源的統(tǒng)一管控,這種能力我們可以稱之為分布式鎖。因此分布式鎖的本質(zhì)就是在不同服務(wù)實(shí)例之外建立一種獲取鎖的機(jī)制,形成一種并發(fā)互斥能力來(lái)確保不同線程對(duì)于共享資源的并發(fā)安全,從而實(shí)現(xiàn)在微服務(wù)架構(gòu)中同一時(shí)刻只有一個(gè)線程可以對(duì)共享資源進(jìn)行操作。對(duì)于分布式鎖來(lái)說(shuō),實(shí)際就是需要一個(gè)外部的狀態(tài)存儲(chǔ)系統(tǒng)來(lái)實(shí)現(xiàn)原子化的排他性操作。

通過(guò)對(duì)于分布式鎖的需求分析,總結(jié)了如下的分布式鎖四大特性,分別是多節(jié)點(diǎn)、加鎖速度快、排他性以及鎖過(guò)期實(shí)現(xiàn)機(jī)制。

分布式鎖實(shí)現(xiàn)方案
基于數(shù)據(jù)庫(kù)的分布式鎖實(shí)現(xiàn)方案
實(shí)現(xiàn)原理
通過(guò)數(shù)據(jù)庫(kù)的方式實(shí)現(xiàn)分布式鎖的效果,實(shí)際就是借助于數(shù)據(jù)庫(kù)的唯一性約束特性或者for update來(lái)實(shí)現(xiàn)。這里以唯一性約束來(lái)舉個(gè)栗子,在電商領(lǐng)域的庫(kù)存服務(wù)負(fù)責(zé)對(duì)商品的庫(kù)存進(jìn)行扣減,首先創(chuàng)建一張專門存放鎖信息的鎖表,那么庫(kù)存服務(wù)在進(jìn)行庫(kù)存操作之前,先向數(shù)據(jù)庫(kù)中的鎖表插入一條鎖資源數(shù)據(jù)。
create table ‘distributed_lock' ( ‘id' BIGINT NOT NULL AUTO_INCREMENT, ‘resource_lock_key‘ varchar(64) NOT NULL PRIMARY KEY(‘id'), UNIQUE KEY ‘uk_resource_lock_key‘ (‘resource_lock_key‘) USING BTREE )
大致的交互流程如下:
1、當(dāng)庫(kù)存服務(wù)進(jìn)行手機(jī)庫(kù)存扣減的時(shí)候,首先先向數(shù)據(jù)庫(kù)中的鎖表當(dāng)中插入一條資源鎖信息;
2、如果插入成功,則表示庫(kù)存服務(wù)1可以對(duì)手機(jī)庫(kù)存進(jìn)行庫(kù)存扣減操作;
3、此時(shí)庫(kù)存服務(wù)2也要對(duì)庫(kù)存進(jìn)行操作,于是同樣插入數(shù)據(jù)到鎖表中;
4、但是由于鎖表設(shè)置了唯一性約束,鎖信息插入失敗,庫(kù)存服務(wù)進(jìn)行等待;
5、庫(kù)存服務(wù)1執(zhí)行完庫(kù)存扣減之后,刪除鎖表的信息;
6、庫(kù)存服務(wù)2嘗試插入資源鎖信息,發(fā)現(xiàn)可以插入成功,繼續(xù)執(zhí)行后續(xù)操作。

方案分析
基于數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方式,看起來(lái)還是比較容易理解的。但是實(shí)際上還是有一些問(wèn)題存在的,我們一起來(lái)分析下。
1、性能問(wèn)題:由于是插入數(shù)據(jù)數(shù)據(jù)需要落盤存儲(chǔ),如果平凡進(jìn)行讀寫的話會(huì)影響數(shù)據(jù)庫(kù)性能,另外由于使用唯一鍵進(jìn)行判斷也會(huì)一定程度上影響數(shù)據(jù)庫(kù)性能,因此數(shù)據(jù)庫(kù)方案適用于并發(fā)量不到的簡(jiǎn)單場(chǎng)景;
2、數(shù)據(jù)庫(kù)如果單點(diǎn)部署的話會(huì)存在單點(diǎn)故障問(wèn)題,如果數(shù)據(jù)庫(kù)出現(xiàn)故障,可能會(huì)導(dǎo)致平臺(tái)中的業(yè)務(wù)異常;
3、死鎖問(wèn)題:在上文介紹中,包含了插入數(shù)據(jù)庫(kù)的獲取鎖的步驟,還包含了刪除鎖信息的釋放鎖的過(guò)程,但是如果庫(kù)存服務(wù)1在加鎖之后掛掉了,無(wú)法進(jìn)行鎖的釋放,而其他服務(wù)又無(wú)法獲取到鎖就會(huì)造成死鎖的問(wèn)題。當(dāng)然了我們可以通過(guò)一個(gè)定時(shí)任務(wù)去檢查鎖表中是不是有過(guò)時(shí)的鎖資源。但是這樣無(wú)疑增加了分布式鎖實(shí)現(xiàn)的復(fù)雜性。
4、不支持可重入:如果想要實(shí)現(xiàn)可重入鎖,還需要增加主機(jī)、線程名等字段來(lái)進(jìn)行標(biāo)注,通過(guò)這幾個(gè)字段來(lái)判斷和當(dāng)前信息是否一致,如果一致則認(rèn)為已經(jīng)獲取到了鎖。 鑒于以上的這些問(wèn)題,有沒有其他的分布式實(shí)現(xiàn)方案可以避免上述存在的問(wèn)題呢?我們?cè)偻聛?lái)看。
基于Redis的分布式鎖實(shí)現(xiàn)方案
基于sentnx命令的實(shí)現(xiàn)原理
Redis作為一塊高性能的數(shù)據(jù)庫(kù)中間件,經(jīng)常被當(dāng)做緩存在項(xiàng)目中使用。因此通過(guò)Redis實(shí)現(xiàn)分布式鎖,也是比較常見的實(shí)現(xiàn)方案。 一樣的道理,通過(guò)Redis實(shí)現(xiàn)分布式鎖也需要通過(guò)它實(shí)現(xiàn)鎖的互斥的能力。實(shí)際上就是利用了sentnx(set if not exists)命令。同時(shí)該命令是否能夠設(shè)置成功,決定服務(wù)是否可以拿到對(duì)應(yīng)的分布式鎖。
127.0.0.1:6379> setnx stockLock 10.12.35.12_stockService
(integer) 1

如上圖所示,大致的加鎖以及釋放鎖的過(guò)程其實(shí)和數(shù)據(jù)庫(kù)的分布式鎖方案還是比較類似的。只不過(guò)將其中向數(shù)據(jù)庫(kù)插入數(shù)據(jù)的步驟替換成了向Redis獲取鎖的步驟,由于Redis是基于內(nèi)存進(jìn)行操作的,因此性能上比基于數(shù)據(jù)庫(kù)的分布式鎖方案更好一點(diǎn)。
方案分析
上述基于Redis的方案的方案在性能上具有優(yōu)勢(shì),我們?cè)賮?lái)分析下,這個(gè)使用命令的方式有沒有什么問(wèn)題。實(shí)際上和前面的數(shù)據(jù)庫(kù)方案類似,Redis也會(huì)有死鎖問(wèn)題,當(dāng)獲取鎖之后如果庫(kù)存服務(wù)1掛掉了,庫(kù)存服務(wù)2就獲取不到鎖了。因此我們要對(duì)其進(jìn)行優(yōu)化。那么問(wèn)題的本質(zhì)是如何讓鎖可以釋放,因此我們需要在設(shè)置鎖的時(shí)候加上過(guò)期時(shí)間,這樣即使庫(kù)存服務(wù)1掛了,無(wú)法主動(dòng)釋放鎖,那么到了過(guò)期時(shí)間后鎖失效,庫(kù)存服務(wù)2依然可以獲取鎖,不會(huì)再造成死鎖問(wèn)題。

另外還應(yīng)該注意的是,在我們?cè)O(shè)置鎖的時(shí)候,還需要帶有自身服務(wù)的業(yè)務(wù)屬性,否則容易造成錯(cuò)亂。為什么這么說(shuō)呢?舉個(gè)栗子,庫(kù)存服務(wù)在加完鎖之后開始執(zhí)行扣減庫(kù)存的任務(wù),當(dāng)扣減庫(kù)存完成之后,服務(wù)掛了,原先需要?jiǎng)h除的鎖資源,等到過(guò)期之后被Redis刪除,此時(shí)庫(kù)存服務(wù)2可以繼續(xù)申請(qǐng)鎖,如果此時(shí)庫(kù)存服務(wù)1恢復(fù)了,它并不知道鎖資源已經(jīng)釋放,起來(lái)后立馬刪除了庫(kù)存服務(wù)2加的鎖,那么此時(shí)就會(huì)出現(xiàn)兩個(gè)問(wèn)題:
1、庫(kù)存服務(wù)執(zhí)行完庫(kù)存扣減之后,回頭來(lái)進(jìn)行鎖資源釋放的時(shí)候,發(fā)現(xiàn)鎖實(shí)際已經(jīng)不在了;
2、當(dāng)庫(kù)存服務(wù)1恢復(fù)后發(fā)現(xiàn)鎖還在,立馬刪除了該鎖,完成了它掛掉之前未完成的工作。但是實(shí)際上這個(gè)鎖是庫(kù)存服務(wù)2加的鎖,如果此時(shí)庫(kù)存服務(wù)3也要嘗試加鎖,發(fā)現(xiàn)可以加鎖成功,和庫(kù)存服務(wù)2一樣同樣對(duì)庫(kù)存進(jìn)行操作,那么此時(shí)就會(huì)出現(xiàn)線程安全問(wèn)題。

經(jīng)過(guò)上文的分析,這個(gè)問(wèn)題的根源就是在加鎖的時(shí)候沒有具體區(qū)分到底是哪個(gè)服務(wù)加的鎖。因此在執(zhí)行命令的時(shí)候,我們需要將帶有服務(wù)實(shí)例關(guān)聯(lián)屬性的設(shè)置為value,這樣在進(jìn)行鎖獲取的時(shí)候檢查下當(dāng)前鎖的持有者是誰(shuí),如果不是服務(wù)實(shí)例自己則不能執(zhí)行刪除操作。
那這樣是不是就完美解決問(wèn)題了呢?實(shí)際上還是有問(wèn)題存在的,有同學(xué)會(huì)說(shuō),怎么這么多問(wèn)題?實(shí)際上這種方案的實(shí)現(xiàn)就是在各種不完美的方案中逐漸找到相對(duì)完美的方案。
上文提到的獲取鎖判斷是不是自己方服務(wù)實(shí)例加的鎖,再執(zhí)行刪除鎖的過(guò)程實(shí)際并不是原子的。因此還是會(huì)出現(xiàn)并發(fā)安全問(wèn)題,這個(gè)問(wèn)題可以通過(guò)lua腳本來(lái)解決,在lua腳本中實(shí)現(xiàn)這個(gè)邏輯,而不是在客戶端中實(shí)現(xiàn)。 但是實(shí)際上還是有問(wèn)題沒有解決,比如說(shuō)我們?cè)诩渔i的時(shí)候會(huì)設(shè)置過(guò)期時(shí)間,但是過(guò)期時(shí)間應(yīng)該設(shè)置多長(zhǎng)時(shí)間呢?設(shè)置短了的話,出現(xiàn)網(wǎng)絡(luò)超時(shí)或者服務(wù)還沒有執(zhí)行完業(yè)務(wù),鎖就失效了。設(shè)置長(zhǎng)了話,其他服務(wù)節(jié)點(diǎn)等待獲取鎖的時(shí)間就會(huì)變長(zhǎng),降低了服務(wù)的性能。
基于Redisson實(shí)現(xiàn)
Redisson實(shí)際上就是一個(gè)封裝了Redis操作的客戶端,實(shí)現(xiàn)了對(duì)于常見的Redis操作的封裝。如對(duì)于Redis的設(shè)置鎖的步驟以及刪除鎖的步驟都進(jìn)行了封裝。在設(shè)置鎖的操作中,還引入了自動(dòng)給鎖續(xù)期的機(jī)制,SDK檢測(cè)到業(yè)務(wù)未完成,但是鎖要到期后,執(zhí)行定續(xù)期。這樣并可以動(dòng)態(tài)的調(diào)節(jié)過(guò)期時(shí)間,避免鎖在業(yè)務(wù)未完成情況下被釋放的問(wèn)題。

同時(shí)還封裝了刪除鎖的時(shí)候執(zhí)行的業(yè)務(wù)判斷后再刪除的邏輯,這樣我們?cè)谑褂?code>Redisson操作Redis的時(shí)候,就和我們使用JDK一樣。
RedLock
為了解決Redis作為分布式鎖存在的單點(diǎn)問(wèn)題,Redis的作者又提出了Redlock的解決方案,該解決方案依賴多個(gè)Redis的Master節(jié)點(diǎn),官方推薦使用5個(gè)Master節(jié)點(diǎn),他們彼此之間是獨(dú)立的。大致的交互步驟如下所示:
1、首先獲取當(dāng)前節(jié)點(diǎn)的系統(tǒng)時(shí)間;
2、客戶端嘗試向所有的Redis實(shí)例順序地發(fā)送加鎖的請(qǐng)求(官方推薦Redis集群至少5個(gè)實(shí)例),在設(shè)置鎖的過(guò)程中,使用相同的key以及隨機(jī)值value,同時(shí)請(qǐng)求的超時(shí)時(shí)間需要遠(yuǎn)小于鎖的有效時(shí)間。這樣做的目的是為了防止節(jié)點(diǎn)不可用的時(shí)候?qū)е抡?qǐng)求鎖的時(shí)候被阻塞,當(dāng)實(shí)例沒響應(yīng)的時(shí)候可以快速跳過(guò),向下一個(gè)節(jié)點(diǎn)繼續(xù)請(qǐng)求鎖。
3、假設(shè)Redis集群規(guī)模為5,那么如果客戶端在大多數(shù)實(shí)例中(超過(guò)3個(gè)實(shí)例)獲得了鎖,同時(shí)計(jì)算了當(dāng)前的時(shí)間減去步驟1中獲得的時(shí)間,這個(gè)事件差如果小于鎖的有效時(shí)間,那么此時(shí)可以認(rèn)為加鎖成功,可以操作執(zhí)行后續(xù)的業(yè)務(wù);
4、如果不滿足步驟3是條件,那么就表示加鎖失敗,客戶端需要向所有的Redis節(jié)點(diǎn)發(fā)起鎖釋放請(qǐng)求。

方案分析
為什么Redlock要在集群中多個(gè)實(shí)例上加鎖呢?實(shí)際目的是通過(guò)鎖的冗余來(lái)實(shí)現(xiàn)分布式鎖的高容錯(cuò)性。試想一下如果只有一個(gè)Redis實(shí)例,一旦它掛掉了,客戶端就無(wú)法進(jìn)行加鎖操作了或者鎖信息就會(huì)丟失,影響業(yè)務(wù)功能。通過(guò)在集群中多實(shí)例中冗余鎖信息,即使出現(xiàn)Redis掛了的情況,其他節(jié)點(diǎn)中依然存在鎖信息,從而提升了分布式鎖的可用性。
那么為什么還要計(jì)算幾所時(shí)間呢?由于我們加鎖的時(shí)候,每個(gè)節(jié)點(diǎn)都設(shè)置了超時(shí)時(shí)間,如果整個(gè)加鎖的時(shí)間過(guò)長(zhǎng),整個(gè)過(guò)程的累加時(shí)間超過(guò)了鎖的有效時(shí)間,那么加鎖完成之后就會(huì)哦出現(xiàn)鎖失效的情況了,因此我們需要確保加鎖的事件盡可能的短,這也是為什么加鎖請(qǐng)求都有超時(shí)時(shí)間的原因了,發(fā)現(xiàn)超時(shí)立馬跳到下一個(gè)節(jié)點(diǎn),避免單個(gè)節(jié)點(diǎn)耗時(shí)過(guò)長(zhǎng)。
雖然Redlock看上去是比較完善的分布式解決方案,但是實(shí)際上這個(gè)方案是比較重的,需要維護(hù)一個(gè)Redis集群,另外過(guò)程中依賴系統(tǒng)時(shí)間,但是如果出現(xiàn)了時(shí)間跳變,那么對(duì)于整個(gè)分布式鎖都有非常大的影響。
基于Zookeeper的分布式鎖實(shí)現(xiàn)方案
實(shí)現(xiàn)原理
Zookeeper是一個(gè)分布式的應(yīng)用協(xié)調(diào)服務(wù)中間件,通過(guò)它也可以實(shí)現(xiàn)分布式鎖的效果,這里介紹的是基于臨時(shí)有序的ZNode分布式鎖實(shí)現(xiàn)方案。在介紹方案之前,先補(bǔ)充下Zookeeper中和分布式鎖息息相關(guān)的特性。
我們來(lái)看下Zookeeper的數(shù)據(jù)結(jié)構(gòu),實(shí)際上它是一種樹形模型,類似于Linux的文件系統(tǒng)。Zookeeper使用類似于文件目錄的層級(jí)目錄數(shù)據(jù)結(jié)構(gòu)來(lái)組織自身的數(shù)據(jù)存儲(chǔ)節(jié)點(diǎn),這些節(jié)點(diǎn)就被稱作為ZNode,每個(gè)節(jié)點(diǎn)都用一個(gè)以斜杠(/)分隔的路徑來(lái)表示,而且每個(gè)節(jié)點(diǎn)都有父節(jié)點(diǎn)(根節(jié)點(diǎn)除外)。另外在Zookeeper中,如果我們使用不同的創(chuàng)建參數(shù),可以創(chuàng)建不同類型的ZNode。 1、持久化ZNode:當(dāng)createMode為PERSISTENT會(huì)創(chuàng)建持久化ZNode,節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)會(huì)永久保存在Zookeeper中,如果createMode為PERSISTENT_SEQUENTIAL,則會(huì)創(chuàng)建有序持久化ZNode,和之前的持久化節(jié)點(diǎn)不通的是,有序持久化節(jié)點(diǎn)的節(jié)點(diǎn)名稱會(huì)附加上全局有序的遞增序號(hào); 2、臨時(shí)ZNode:當(dāng)createMode為EPHEMERAL時(shí),創(chuàng)建的節(jié)點(diǎn)臨時(shí)節(jié)點(diǎn),在與客戶端的session過(guò)期后,對(duì)應(yīng)的臨時(shí)節(jié)點(diǎn)也會(huì)被刪除。當(dāng)createMode為EPHEMERAL_SEQUENTIAL時(shí)創(chuàng)建出來(lái)的為有序的臨時(shí)節(jié)點(diǎn),當(dāng)session過(guò)期之后,節(jié)點(diǎn)及其存儲(chǔ)的數(shù)據(jù)也是會(huì)被刪除的。

通過(guò)上述對(duì)于節(jié)點(diǎn)特性的描述,可以看出來(lái)它的全局遞增有序以及過(guò)期刪除的特性與分布式鎖實(shí)現(xiàn)的原理非常契合。因此通過(guò)Zookeeper實(shí)現(xiàn)分布式鎖的大致可以分為以下幾個(gè)步驟:
1、首先創(chuàng)建一個(gè)持久化節(jié)點(diǎn)也就是父節(jié)點(diǎn),這個(gè)持久化節(jié)點(diǎn)代表著一個(gè)分布式鎖實(shí)例;
2、當(dāng)有線程想要申請(qǐng)分布式鎖的時(shí)候,則在該持久化節(jié)點(diǎn)下創(chuàng)建臨時(shí)有序節(jié)點(diǎn);
3、如果此時(shí)新建的臨時(shí)有序節(jié)點(diǎn)是該父節(jié)點(diǎn)小所有有序節(jié)點(diǎn)中序號(hào)最小的節(jié)點(diǎn),那么此時(shí)就表示申請(qǐng)到了分布式鎖;
4、如果新建的臨時(shí)節(jié)點(diǎn)當(dāng)前不是最小序號(hào)的節(jié)點(diǎn),則需要不斷檢查是否最小,知道最終獲取到鎖,或者節(jié)點(diǎn)超時(shí)。實(shí)際上這個(gè)是通過(guò)Zookeeper的watch機(jī)制實(shí)現(xiàn)的,在當(dāng)前節(jié)點(diǎn)的上一序號(hào)的節(jié)點(diǎn)設(shè)置監(jiān)聽器,檢查是否為最小節(jié)點(diǎn)的任務(wù)可以一直阻塞,直到收到上一節(jié)點(diǎn)被刪除的時(shí)間事件,則喚醒檢查事件,檢查當(dāng)前節(jié)點(diǎn)是不是最小序號(hào)節(jié)點(diǎn)。
5、當(dāng)線程執(zhí)行完業(yè)務(wù)之后,可以手動(dòng)刪除該臨時(shí)節(jié)點(diǎn)以便于釋放持有的鎖。另外即使服務(wù)掛掉,由于對(duì)應(yīng)的session失效,對(duì)應(yīng)的臨時(shí)節(jié)點(diǎn)也會(huì)被刪除,防止出現(xiàn)死鎖問(wèn)題。

和Redisson類似,我們?cè)趯?shí)際使用Zookeeper作為分布式鎖的時(shí)候可以用Curator來(lái)作為開發(fā)SDK,它同樣封裝了很多實(shí)現(xiàn),包括可重入鎖的實(shí)現(xiàn),減輕了使用者的負(fù)擔(dān)。
方案分析
看上去通過(guò)Zookeeper實(shí)現(xiàn)分布式鎖還是比較好的一種解決方案,但是它是完美的嗎?從上面的分布式鎖的流程可知,客戶端線程想要獲取鎖就需要?jiǎng)?chuàng)建臨時(shí)節(jié)點(diǎn),這個(gè)時(shí)候客戶端和Zookeeper之間就會(huì)維護(hù)一個(gè)session,來(lái)表示該客戶端還在排隊(duì)等待獲取鎖。因此這個(gè)方案的潛在問(wèn)題就在于一旦出現(xiàn)網(wǎng)絡(luò)異常,或者客戶端發(fā)生STW GC,那么就可能導(dǎo)致session關(guān)閉,從而導(dǎo)致臨時(shí)節(jié)點(diǎn)被關(guān)閉,此時(shí)就會(huì)出現(xiàn)原來(lái)客戶端持有的鎖被刪除了,如果有另外的客戶端過(guò)來(lái)加鎖的話可以成功獲取,那么此時(shí)就出現(xiàn)并發(fā)安全問(wèn)題了。因此在這種極端條件下,Zookeeper的分布式鎖實(shí)現(xiàn)方案也不是100%保證安全的。
另外實(shí)際上還有基于etcd的分布式鎖實(shí)現(xiàn)方案,其基本原理和Zookeeper差不多,感興趣的同學(xué)可以再進(jìn)行了解下。
分布式鎖方案到底選哪個(gè)?
通過(guò)上述幾種分布式鎖方案原理的闡述以及問(wèn)題分析,每個(gè)方案都有自己的長(zhǎng)處以及缺點(diǎn)。所以在實(shí)際項(xiàng)目落地的時(shí)候,我么需要結(jié)合實(shí)際來(lái)進(jìn)行分布式鎖方案的選擇。比如如果平臺(tái)中本身已經(jīng)有Redis集群了,但是沒有Zookeeper集群,那么我們就可以借助于現(xiàn)有的基礎(chǔ)實(shí)施來(lái)落地分布式鎖,不需要再去維護(hù)一套Zookeeper集群。
另外根據(jù)實(shí)際的業(yè)務(wù)場(chǎng)景,如果并發(fā)量并不是很高,也可以通過(guò)簡(jiǎn)單的數(shù)據(jù)庫(kù)的分布式鎖方案來(lái)實(shí)現(xiàn)。
總結(jié)
本文首先對(duì)從單機(jī)時(shí)代到分布式場(chǎng)景下的分布式鎖的產(chǎn)生的背景進(jìn)行了分析,通過(guò)對(duì)分布式鎖的本質(zhì)問(wèn)題的探究,引出了數(shù)據(jù)庫(kù)分布式鎖方案、Redis分布式鎖方案以及Zookeeper分布式鎖方案,并對(duì)每一種方案的優(yōu)點(diǎn)以及不足進(jìn)行了分析,相信大家可以在落地實(shí)現(xiàn)分布式鎖的時(shí)候可以按照自身的情況選擇合適的方案。
到此這篇關(guān)于深入淺出探索Java分布式鎖原理的文章就介紹到這了,更多相關(guān)Java 分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java深入講解二十三種設(shè)計(jì)模式之中的策略模式
策略模式屬于Java 23種設(shè)計(jì)模式中行為模式之一,該模式定義了一系列算法,并將每個(gè)算法封裝起來(lái),使它們可以相互替換,且算法的變化不會(huì)影響使用算法的客戶。本文將通過(guò)示例詳細(xì)講解這一模式,需要的可以參考一下2022-05-05
淺談Spring框架中@Autowired和@Resource的區(qū)別
最近review別人代碼的時(shí)候,看到了一些@Autowired不一樣的用法,覺得有些意思,下面這篇文章主要給大家介紹了關(guān)于Spring框架中@Autowired和@Resource區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-10-10
java設(shè)計(jì)模式:建造者模式之生產(chǎn)線
這篇文章主要介紹了Java設(shè)計(jì)模式之建造者模式,結(jié)合具體實(shí)例形式分析了建造者模式的概念、原理、實(shí)現(xiàn)方法與相關(guān)使用注意事項(xiàng),需要的朋友可以參考下2021-08-08
Redisson 分布式延時(shí)隊(duì)列 RedissonDelayedQueue 運(yùn)行流程
這篇文章主要介紹了Redisson分布式延時(shí)隊(duì)列 RedissonDelayedQueue運(yùn)行流程,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
在SpringBoot中使用MongoDB的簡(jiǎn)單場(chǎng)景案例
MongoDB 是一種非關(guān)系型數(shù)據(jù)庫(kù),也被稱為 NoSQL 數(shù)據(jù)庫(kù),它主要以文檔的形式存儲(chǔ)數(shù)據(jù),本文給大家介紹了在SpringBoot中使用MongoDB的簡(jiǎn)單場(chǎng)景案例,并通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-09-09

