1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        11 張圖深入理解分布式鎖原理

        共 6309字,需瀏覽 13分鐘

         ·

        2022-05-30 20:46

        什么是分布式鎖?它能干什么

        單體系統(tǒng)中,在高并發(fā)場(chǎng)景下想要訪(fǎng)問(wèn)共享資源的時(shí)候,我們需要通過(guò)加鎖的方式來(lái)保證共享資源并發(fā)的安全性,確保在同一時(shí)刻只有一個(gè)線(xiàn)程對(duì)共享資源進(jìn)行操作。相信大家對(duì)于 Java 提供的 synchronized 關(guān)鍵字以及 Lock 鎖都不陌生,在實(shí)際的項(xiàng)目中大家都使用過(guò)。如下圖所示,在同一個(gè) JVM 進(jìn)程中,Thread1 獲得鎖之后,對(duì)共享資源進(jìn)行操作,其他線(xiàn)程未獲得鎖的線(xià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)景下不能滿(mǎn)足共享資源的并發(fā)訪(fǎng)問(wèn)要求。因此我們需要一種適用于分布式場(chǎng)景下的共享資源安全的處理機(jī)制,此時(shí)應(yīng)對(duì)這種問(wèn)題的分布式鎖就應(yīng)運(yùn)而生了。


        既然 JVM 進(jìn)程管不到其他服務(wù)實(shí)例的線(xiàn)程,那么可以借助于外部組件能力來(lái)實(shí)現(xiàn)不同服務(wù)實(shí)例對(duì)于共享資源的統(tǒng)一管控,這種能力我們可以稱(chēng)之為分布式鎖。因此分布式鎖的本質(zhì)就是在不同服務(wù)實(shí)例之外建立一種獲取鎖的機(jī)制,形成一種并發(fā)互斥能力來(lái)確保不同線(xiàn)程對(duì)于共享資源的并發(fā)安全,從而實(shí)現(xiàn)在微服務(wù)架構(gòu)中同一時(shí)刻只有一個(gè)線(xiàn)程可以對(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)方案

        2.1 基于數(shù)據(jù)庫(kù)的分布式鎖實(shí)現(xiàn)方案

        2.1.1實(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)建一張專(zhuān)門(mén)存放鎖信息的鎖表,那么庫(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ù)操作。


        2.1.2 方案分析

        基于數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方式,看起來(lái)還是比較容易理解的。但是實(shí)際上還是有一些問(wèn)題存在的,我們一起來(lái)分析下。

        1、性能問(wèn)題:由于是插入數(shù)據(jù)數(shù)據(jù)需要落盤(pán)存儲(chǔ),如果平凡進(jìn)行讀寫(xiě)的話(huà)會(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à)會(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ī)、線(xiàn)程名等字段來(lái)進(jìn)行標(biāo)注,通過(guò)這幾個(gè)字段來(lái)判斷和當(dāng)前信息是否一致,如果一致則認(rèn)為已經(jīng)獲取到了鎖。

        鑒于以上的這些問(wèn)題,有沒(méi)有其他的分布式實(shí)現(xiàn)方案可以避免上述存在的問(wèn)題呢?我們?cè)偻聛?lái)看。


        2.2 基于 Redis 的分布式鎖實(shí)現(xiàn)方案

        2.2.1 基于 sentnx 命令的實(shí)現(xiàn)原理

        Redis 作為一塊高性能的數(shù)據(jù)庫(kù)中間件,經(jīng)常被當(dāng)做緩存在項(xiàng)目中使用。因此通過(guò) Redis 實(shí)現(xiàn)分布式鎖,也是比較常見(jià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ù)的分布式鎖方案還是比較類(lèi)似的。只不過(guò)將其中向數(shù)據(jù)庫(kù)插入數(shù)據(jù)的步驟替換成了向 Redis 獲取鎖的步驟,由于 Redis 是基于內(nèi)存進(jìn)行操作的,因此性能上比基于數(shù)據(jù)庫(kù)的分布式鎖方案更好一點(diǎn)。


        2.2.2 原理分析

        上述基于 Redis 的方案的方案在性能上具有優(yōu)勢(shì),我們?cè)賮?lái)分析下,這個(gè)使用命令的方式有沒(méi)有什么問(wèn)題。實(shí)際上和前面的數(shù)據(jù)庫(kù)方案類(lèi)似,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ù)在加完鎖之后開(kāi)始執(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)線(xiàn)程安全問(wèn)題。


        經(jīng)過(guò)上文的分析,這個(gè)問(wèn)題的根源就是在加鎖的時(shí)候沒(méi)有具體區(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è)邏輯,而不是在客戶(hù)端中實(shí)現(xiàn)。


        但是實(shí)際上還是有問(wèn)題沒(méi)有解決,比如說(shuō)我們?cè)诩渔i的時(shí)候會(huì)設(shè)置過(guò)期時(shí)間,但是過(guò)期時(shí)間應(yīng)該設(shè)置多長(zhǎng)時(shí)間呢?設(shè)置短了的話(huà),出現(xiàn)網(wǎng)絡(luò)超時(shí)或者服務(wù)還沒(méi)有執(zhí)行完業(yè)務(wù),鎖就失效了。設(shè)置長(zhǎng)了話(huà),其他服務(wù)節(jié)點(diǎn)等待獲取鎖的時(shí)間就會(huì)變長(zhǎng),降低了服務(wù)的性能。

        2.2.3 基于 Redisson 實(shí)現(xiàn)

        Redisson 實(shí)際上就是一個(gè)封裝了 Redis 操作的客戶(hù)端,實(shí)現(xiàn)了對(duì)于常見(jiàn)的 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è)谑褂?Redisson 操作 Redis 的時(shí)候,就和我們使用 JDK 一樣。


        2.2.4 RedLock

        為了解決 Redis 作為分布式鎖存在的單點(diǎn)問(wèn)題,Redis 的作者又提出了 Redlock 的解決方案,該解決方案依賴(lài)多個(gè) Redis 的 Master 節(jié)點(diǎn),官方推薦使用 5 個(gè) Master 節(jié)點(diǎn),他們彼此之間是獨(dú)立的。大致的交互步驟如下所示:

        1、首先獲取當(dāng)前節(jié)點(diǎn)的系統(tǒng)時(shí)間;

        2、客戶(hù)端嘗試向所有的 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í)例沒(méi)響應(yīng)的時(shí)候可以快速跳過(guò),向下一個(gè)節(jié)點(diǎn)繼續(xù)請(qǐng)求鎖。

        3、假設(shè) Redis 集群規(guī)模為 5,那么如果客戶(hù)端在大多數(shù)實(shí)例中(超過(guò) 3 個(gè)實(shí)例)獲得了鎖,同時(shí)計(jì)算了當(dāng)前的時(shí)間減去步驟 1 中獲得的時(shí)間,這個(gè)事件差如果小于鎖的有效時(shí)間,那么此時(shí)可以認(rèn)為加鎖成功,可以操作執(zhí)行后續(xù)的業(yè)務(wù);

        4、如果不滿(mǎn)足步驟 3 是條件,那么就表示加鎖失敗,客戶(hù)端需要向所有的 Redis 節(jié)點(diǎn)發(fā)起鎖釋放請(qǐng)求。


        2.2.5 方案分析

        為什么 Redlock 要在集群中多個(gè)實(shí)例上加鎖呢?實(shí)際目的是通過(guò)鎖的冗余來(lái)實(shí)現(xiàn)分布式鎖的高容錯(cuò)性。試想一下如果只有一個(gè) Redis 實(shí)例,一旦它掛掉了,客戶(hù)端就無(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ò)程中依賴(lài)系統(tǒng)時(shí)間,但是如果出現(xiàn)了時(shí)間跳變,那么對(duì)于整個(gè)分布式鎖都有非常大的影響。


        2.3 基于 Zookeeper 的分布式鎖實(shí)現(xiàn)方案

        2.3.1 實(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í)際上它是一種樹(shù)形模型,類(lèi)似于 Linux 的文件系統(tǒng)。Zookeeper 使用類(lèi)似于文件目錄的層級(jí)目錄數(shù)據(jù)結(jié)構(gòu)來(lái)組織自身的數(shù)據(jù)存儲(chǔ)節(jié)點(diǎn),這些節(jié)點(diǎn)就被稱(chēng)作為 ZNode,每個(gè)節(jié)點(diǎn)都用一個(gè)以斜杠(/)分隔的路徑來(lái)表示,而且每個(gè)節(jié)點(diǎn)都有父節(jié)點(diǎn)(根節(jié)點(diǎn)除外)。另外在 Zookeeper 中,如果我們使用不同的創(chuàng)建參數(shù),可以創(chuàng)建不同類(lèi)型的 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)名稱(chēng)會(huì)附加上全局有序的遞增序號(hào);

        2、臨時(shí) ZNode:當(dāng) createMode 為 EPHEMERAL 時(shí),創(chuàng)建的節(jié)點(diǎn)臨時(shí)節(jié)點(diǎn),在與客戶(hù)端的 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)有線(xiàn)程想要申請(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)聽(tīng)器,檢查是否為最小節(jié)點(diǎn)的任務(wù)可以一直阻塞,直到收到上一節(jié)點(diǎn)被刪除的時(shí)間事件,則喚醒檢查事件,檢查當(dāng)前節(jié)點(diǎn)是不是最小序號(hào)節(jié)點(diǎn)。

        5、當(dāng)線(xiàn)程執(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 類(lèi)似,我們?cè)趯?shí)際使用 Zookeeper 作為分布式鎖的時(shí)候可以用 Curator 來(lái)作為開(kāi)發(fā) SDK,它同樣封裝了很多實(shí)現(xiàn),包括可重入鎖的實(shí)現(xiàn),減輕了使用者的負(fù)擔(dān)。

        2.3.2 方案分析

        看上去通過(guò) Zookeeper 實(shí)現(xiàn)分布式鎖還是比較好的一種解決方案,但是它是完美的嗎?從上面的分布式鎖的流程可知,客戶(hù)端線(xiàn)程想要獲取鎖就需要?jiǎng)?chuàng)建臨時(shí)節(jié)點(diǎn),這個(gè)時(shí)候客戶(hù)端和 Zookeeper 之間就會(huì)維護(hù)一個(gè) session,來(lái)表示該客戶(hù)端還在排隊(duì)等待獲取鎖。因此這個(gè)方案的潛在問(wèn)題就在于一旦出現(xiàn)網(wǎng)絡(luò)異常,或者客戶(hù)端發(fā)生 STW GC,那么就可能導(dǎo)致 session 關(guān)閉,從而導(dǎo)致臨時(shí)節(jié)點(diǎn)被關(guān)閉,此時(shí)就會(huì)出現(xiàn)原來(lái)客戶(hù)端持有的鎖被刪除了,如果有另外的客戶(hù)端過(guò)來(lái)加鎖的話(huà)可以成功獲取,那么此時(shí)就出現(xiàn)并發(fā)安全問(wèn)題了。因此在這種極端條件下,Zookeeper 的分布式鎖實(shí)現(xiàn)方案也不是 100%保證安全的。

        另外實(shí)際上還有基于 etcd 的分布式鎖實(shí)現(xiàn)方案,其基本原理和 Zookeeper 差不多,感興趣的同學(xué)可以再進(jìn)行了解下。

        分布式鎖方案改怎么選?

        通過(guò)上述幾種分布式鎖方案原理的闡述以及問(wèn)題分析,每個(gè)方案都有自己的長(zhǎng)處以及缺點(diǎn)。所以在實(shí)際項(xiàng)目落地的時(shí)候,我么需要結(jié)合實(shí)際來(lái)進(jìn)行分布式鎖方案的選擇。比如如果平臺(tái)中本身已經(jīng)有 Redis 集群了,但是沒(méi)有 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í)候可以按照自身的情況選擇合適的方案。


        瀏覽 56
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            有码一区二区三区 | 成人综合伊人 | 成人免费乱码大片a毛片蜜芽 | www.天天日 | 寡妇高潮一级毛片免费视频 | 国产高清在线 | 日本黄色免费视频网站 | 日本三级韩国三级美三级91 | 亚洲一级免费在线观看 | 男欢女爱a做片 |