国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

如何使用 Redis 快速實(shí)現(xiàn)分布式鎖?

這篇具有很好參考價(jià)值的文章主要介紹了如何使用 Redis 快速實(shí)現(xiàn)分布式鎖?。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

本文我們來討論如何使用 Redis 快速實(shí)現(xiàn)分布式鎖。

分布式鎖有很多種解決方案,前面簡(jiǎn)單介紹過,Redis 可以通過 set key 方式來實(shí)現(xiàn)分布式鎖,但實(shí)際情況要更加復(fù)雜,比如如何確保臨界資源的串行執(zhí)行,如何及時(shí)釋放,都是需要額外考慮的。

本文要講的是一個(gè)完備的分布式鎖應(yīng)該具備哪些特性,以及如何使用 Redis 來一步步優(yōu)化實(shí)現(xiàn)。
分布式鎖需要具有哪些特點(diǎn)
先來看一下,一個(gè)完備的分布式鎖,需要支持哪些特性?

如何使用 Redis 快速實(shí)現(xiàn)分布式鎖?,分布式,中間件,分布式,分布式鎖,redis

一般來說,生產(chǎn)環(huán)境可用的分布式鎖需要滿足以下幾點(diǎn):

  • 互斥性,互斥是鎖的基本特征,同一時(shí)刻只能有一個(gè)線程持有鎖,執(zhí)行臨界操作;
  • 超時(shí)釋放,超時(shí)釋放是鎖的另一個(gè)必備特性,可以對(duì)比 MySQL InnoDB 引擎中的 innodb_lock_wait_timeout 配置,通過超時(shí)釋放,防止不必要的線程等待和資源浪費(fèi);
  • 可重入性,在分布式環(huán)境下,同一個(gè)節(jié)點(diǎn)上的同一個(gè)線程如果獲取了鎖之后,再次請(qǐng)求還是可以成功;
  • 高性能和高可用,加鎖和解鎖的開銷要盡可能的小,同時(shí)也需要保證高可用,防止分布式鎖失效;
  • 支持阻塞和非阻塞性,對(duì)比 Java 語(yǔ)言中的 wait() 和 notify() 等操作,這個(gè)一般是在業(yè)務(wù)代碼中實(shí)現(xiàn),比如在獲取鎖時(shí)通過 while(true) 或者輪詢來實(shí)現(xiàn)阻塞操作。

可以看到,實(shí)現(xiàn)一個(gè)相對(duì)完備的分布式鎖,并不是鎖住資源就可以了,還需要滿足一些額外的特性,否則會(huì)在業(yè)務(wù)開發(fā)中出現(xiàn)各種各樣的問題。

下面我們以 Redis 實(shí)現(xiàn)分布式鎖為例,看一下如何優(yōu)化分布式鎖的具體實(shí)現(xiàn)。

使用 setnx 實(shí)現(xiàn)分布式鎖

Redis 支持 setnx 指令,只在 key 不存在的情況下,將 key 的值設(shè)置為 value,若 key 已經(jīng)存在,則 setnx 命令不做任何動(dòng)作。使用 setnx 實(shí)現(xiàn)分布式鎖的方案,獲取鎖的方法很簡(jiǎn)單,只要以該鎖為 key,設(shè)置一個(gè)隨機(jī)的值即可。如果 setnx 返回 1,則說明該進(jìn)程獲得鎖;如果 setnx 返回 0,則說明其他進(jìn)程已經(jīng)獲得了鎖,進(jìn)程不能進(jìn)入臨界區(qū);如果需要阻塞當(dāng)前進(jìn)程,可以在一個(gè)循環(huán)中不斷嘗試 setnx 操作。

if(setnx(key,value)==1){
     try{
        //業(yè)務(wù)處理
     }finally{
       //釋放鎖
       del(key)
     }
}

釋放鎖時(shí)只要?jiǎng)h除對(duì)應(yīng)的 key 就可以,為了防止系統(tǒng)業(yè)務(wù)進(jìn)程出現(xiàn)異常導(dǎo)致鎖無法釋放,使用 Java 中的 try-catch-finally 來完成鎖的釋放。

對(duì)比一下上面說的分布式鎖特性,使用這種方式實(shí)現(xiàn)分布式鎖的問題很明顯:不支持超時(shí)釋放鎖,如果進(jìn)程在加鎖后宕機(jī),則會(huì)導(dǎo)致鎖無法刪除,其他進(jìn)程無法獲得鎖。

使用 setnx 和 expire 實(shí)現(xiàn)

在分布式鎖的實(shí)現(xiàn)中,依賴業(yè)務(wù)線程進(jìn)行鎖的釋放,如果進(jìn)程宕機(jī),那么就會(huì)出現(xiàn)死鎖。Redis 在設(shè)置一個(gè) key 時(shí),支持設(shè)置過期時(shí)間,利用這一點(diǎn),可以在緩存中實(shí)現(xiàn)鎖的超時(shí)釋放,解決死鎖問題。

在使用 setnx 獲取鎖之后,通過 expire 給鎖加一個(gè)過期時(shí)間,利用 Redis 的緩存失效策略,進(jìn)行鎖的超時(shí)清除。

偽代碼如下:

if(setnx(key,value)==1){
     expire(key,expireTime)
     try{
        //業(yè)務(wù)處理
     }finally{
       //釋放鎖
       del(key)
     }
}

通過設(shè)置過期時(shí)間,避免了占鎖到釋放鎖的過程發(fā)生異常而導(dǎo)致鎖無法釋放的問題,但是在 Redis 中,setnx 和 expire 這兩條命令不具備原子性。如果一個(gè)線程在執(zhí)行完 setnx 之后突然崩潰,導(dǎo)致鎖沒有設(shè)置過期時(shí)間,那么這個(gè)鎖就會(huì)一直存在,無法被其他線程獲取。

使用 set 擴(kuò)展命令實(shí)現(xiàn)

為了解決這個(gè)問題,在 Redis 2.8 版本中,擴(kuò)展了 set 命令,支持 set 和 expire 指令組合的原子操作,解決了加鎖過程中失敗的問題。

set 擴(kuò)展參數(shù)的語(yǔ)法如下:

redis> SET key value expireTime nx

nx 表示僅在鍵不存在時(shí)設(shè)置,這樣可以在同一時(shí)間內(nèi)完成設(shè)置值和設(shè)置過期時(shí)間這兩個(gè)操作,防止設(shè)置過期時(shí)間異常導(dǎo)致的死鎖。那么這種方式還存在問題嗎?

使用 setex 方式看起來解決了鎖超時(shí)的問題,但在實(shí)際業(yè)務(wù)中,如果對(duì)超時(shí)時(shí)間設(shè)置不合理,存在這樣一種可能:在加鎖和釋放鎖之間的業(yè)務(wù)邏輯執(zhí)行的太長(zhǎng),以至于超出了鎖的超時(shí)限制,緩存將對(duì)應(yīng) key 刪除,其他線程可以獲取鎖,出現(xiàn)對(duì)加鎖資源的并發(fā)操作。

我們來模擬下這種情況:

  • 客戶端 A 獲取鎖的時(shí)候設(shè)置了 key 的過期時(shí)間為 2 秒,客戶端 A 在獲取到鎖之后,業(yè)務(wù)邏輯方法執(zhí)行了 3 秒;
  • 客戶端 A 獲取的鎖被 Redis 過期機(jī)制自動(dòng)釋放,客戶端 B 請(qǐng)求鎖成功,出現(xiàn)并發(fā)執(zhí)行;
  • 客戶端 A 執(zhí)行完業(yè)務(wù)邏輯后,釋放鎖,刪除對(duì)應(yīng)的 key;
  • 對(duì)應(yīng)鎖已經(jīng)被客戶端 B 獲取到了,客戶端A釋放的鎖實(shí)際是客戶端B持有的鎖。

可以看到,第一個(gè)線程的邏輯還沒執(zhí)行完,第二個(gè)線程也成功獲得了鎖,加鎖的代碼或者資源并沒有得到嚴(yán)格的串行操作,同時(shí)由于疊加了刪除和釋放鎖操作,導(dǎo)致了加鎖的混亂。

如何避免這個(gè)問題呢?首先,基于 Redis 的分布式鎖一般是用于耗時(shí)比較短的瞬時(shí)性任務(wù),業(yè)務(wù)上超時(shí)的可能性較?。黄浯?,在獲取鎖時(shí),可以設(shè)置 value 為一個(gè)隨機(jī)數(shù),在釋放鎖時(shí)進(jìn)行讀取和對(duì)比,確保釋放的是當(dāng)前線程持有的鎖,一般是通過 Redis 結(jié)合 Lua 腳本的方案實(shí)現(xiàn);最后,需要添加完備的日志,記錄上下游數(shù)據(jù)鏈路,當(dāng)出現(xiàn)超時(shí),則需要檢查對(duì)應(yīng)的問題數(shù)據(jù),并且進(jìn)行人工修復(fù)。

分布式鎖的高可用

上面分布式鎖的實(shí)現(xiàn)方案中,都是針對(duì)單節(jié)點(diǎn) Redis 而言的,在生產(chǎn)環(huán)境中,為了保證高可用,避免單點(diǎn)故障,通常會(huì)使用 Redis 集群。

集群下分布式鎖存在哪些問題

集群環(huán)境下,Redis 通過主從復(fù)制來實(shí)現(xiàn)數(shù)據(jù)同步,Redis 的主從復(fù)制(Replication)是異步的,所以單節(jié)點(diǎn)下可用的方案在集群的環(huán)境中可能會(huì)出現(xiàn)問題,在故障轉(zhuǎn)移(Failover) 過程中喪失鎖的安全性。

由于 Redis 集群數(shù)據(jù)同步是異步的,假設(shè) Master 節(jié)點(diǎn)獲取到鎖后在未完成數(shù)據(jù)同步的情況下,發(fā)生節(jié)點(diǎn)崩潰,此時(shí)在其他節(jié)點(diǎn)依然可以獲取到鎖,出現(xiàn)多個(gè)客戶端同時(shí)獲取到鎖的情況。

我們模擬下這個(gè)場(chǎng)景,按照下面的順序執(zhí)行:

  • 客戶端 A 從 Master 節(jié)點(diǎn)獲取鎖;
  • Master 節(jié)點(diǎn)宕機(jī),主從復(fù)制過程中,對(duì)應(yīng)鎖的 key 還沒有同步到 Slave 節(jié)點(diǎn)上;
  • Slave 升級(jí)為 Master 節(jié)點(diǎn),于是集群丟失了鎖數(shù)據(jù);
  • 其他客戶端請(qǐng)求新的 Master 節(jié)點(diǎn),獲取到了對(duì)應(yīng)同一個(gè)資源的鎖;
  • 出現(xiàn)多個(gè)客戶端同時(shí)持有同一個(gè)資源的鎖,不滿足鎖的互斥性。

可以看到,單實(shí)例場(chǎng)景和集群環(huán)境實(shí)現(xiàn)分布式鎖是不同的,關(guān)于集群下如何實(shí)現(xiàn)分布式鎖,Redis 的作者 Antirez(Salvatore Sanfilippo)提出了 Redlock 算法,我們一起看一下。

Redlock 算法的流程

Redlock 算法是在單 Redis 節(jié)點(diǎn)基礎(chǔ)上引入的高可用模式,Redlock 基于 N 個(gè)完全獨(dú)立的 Redis 節(jié)點(diǎn),一般是大于 3 的奇數(shù)個(gè)(通常情況下 N 可以設(shè)置為 5),可以基本保證集群內(nèi)各個(gè)節(jié)點(diǎn)不會(huì)同時(shí)宕機(jī)。

假設(shè)當(dāng)前集群有 5 個(gè)節(jié)點(diǎn),運(yùn)行 Redlock 算法的客戶端依次執(zhí)行下面各個(gè)步驟,來完成獲取鎖的操作:

  • 客戶端記錄當(dāng)前系統(tǒng)時(shí)間,以毫秒為單位;
  • 依次嘗試從 5 個(gè) Redis 實(shí)例中,使用相同的 key 獲取鎖,當(dāng)向 Redis 請(qǐng)求獲取鎖時(shí),客戶端應(yīng)該設(shè)置一個(gè)網(wǎng)絡(luò)連接和響應(yīng)超時(shí)時(shí)間,超時(shí)時(shí)間應(yīng)該小于鎖的失效時(shí)間,避免因?yàn)榫W(wǎng)絡(luò)故障出現(xiàn)的問題;
  • 客戶端使用當(dāng)前時(shí)間減去開始獲取鎖時(shí)間就得到了獲取鎖使用的時(shí)間,當(dāng)且僅當(dāng)從半數(shù)以上的 Redis 節(jié)點(diǎn)獲取到鎖,并且當(dāng)使用的時(shí)間小于鎖失效時(shí)間時(shí),鎖才算獲取成功;
  • 如果獲取到了鎖,key 的真正有效時(shí)間等于有效時(shí)間減去獲取鎖所使用的時(shí)間,減少超時(shí)的幾率;
  • 如果獲取鎖失敗,客戶端應(yīng)該在所有的 Redis 實(shí)例上進(jìn)行解鎖,即使是上一步操作請(qǐng)求失敗的節(jié)點(diǎn),防止因?yàn)榉?wù)端響應(yīng)消息丟失,但是實(shí)際數(shù)據(jù)添加成功導(dǎo)致的不一致。

在 Redis 官方推薦的 Java 客戶端 Redisson 中,內(nèi)置了對(duì) RedLock 的實(shí)現(xiàn)。下面是官方網(wǎng)站的鏈接,感興趣的同學(xué)可以去了解一下:
redis-distlock
redisson-wiki

分布式系統(tǒng)設(shè)計(jì)是實(shí)現(xiàn)復(fù)雜性和收益的平衡,考慮到集群環(huán)境下的一致性問題,也要避免過度設(shè)計(jì)。在實(shí)際業(yè)務(wù)中,一般使用基于單點(diǎn)的 Redis 實(shí)現(xiàn)分布式鎖就可以,出現(xiàn)數(shù)據(jù)不一致,通過人工手段去回補(bǔ)。

總結(jié)

今天分享了如何使用 Redis 來逐步優(yōu)化分布式鎖實(shí)現(xiàn)的相關(guān)內(nèi)容,包括一個(gè)完備的分布式鎖應(yīng)該支持哪些特性,使用 Redis 實(shí)現(xiàn)分布式鎖的幾種不同方式,最后簡(jiǎn)單介紹了一下 Redis 集群下的 RedLock 算法。文章來源地址http://www.zghlxwxcb.cn/news/detail-756574.html

到了這里,關(guān)于如何使用 Redis 快速實(shí)現(xiàn)分布式鎖?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • redis如何實(shí)現(xiàn)分布式鎖?

    首先,“分布式鎖”的概念,是相對(duì)“本地鎖”而言。 本地鎖比如java中的synchronized 這類 JDK 自帶的 本地鎖 ,來控制一個(gè) JVM 進(jìn)程內(nèi)的多個(gè)線程對(duì)本地共享資源的訪問。 同一時(shí)刻只有一個(gè)線程可以獲取到本地鎖訪問共享資源。 分布式系統(tǒng)下,不同的服務(wù)/客戶端通常運(yùn)

    2024年02月06日
    瀏覽(21)
  • 使用redis實(shí)現(xiàn)分布式鎖

    使用redis實(shí)現(xiàn)分布式鎖

    在一個(gè)分布式系統(tǒng)中,也會(huì)涉及多個(gè)節(jié)點(diǎn)訪問同一個(gè)公共資源的情況,此時(shí)就需要通過鎖來做互斥控制,避免出現(xiàn)類似于“線程安全”的問題,而java的synchronized這樣的鎖只能在當(dāng)前進(jìn)程中生效,在分布式的這種多個(gè)進(jìn)程多個(gè)主機(jī)的場(chǎng)景無能為力,此時(shí)就需要分布式鎖。 例如

    2024年02月07日
    瀏覽(36)
  • 使用注解實(shí)現(xiàn)REDIS分布式鎖

    使用注解實(shí)現(xiàn)REDIS分布式鎖

    有些業(yè)務(wù)請(qǐng)求,屬于耗時(shí)操作,需要加鎖,防止后續(xù)的并發(fā)操作,同時(shí)對(duì)數(shù)據(jù)庫(kù)的數(shù)據(jù)進(jìn)行操作,需要避免對(duì)之前的業(yè)務(wù)造成影響。 使用 Redis 作為分布式鎖,將鎖的狀態(tài)放到 Redis 統(tǒng)一維護(hù),解決集群中單機(jī) JVM 信息不互通的問題,規(guī)定操作順序,保護(hù)用戶的數(shù)據(jù)正確。 梳理

    2024年02月02日
    瀏覽(21)
  • SpringBoot使用Redis實(shí)現(xiàn)分布式緩存

    SpringBoot使用Redis實(shí)現(xiàn)分布式緩存

    ?作者簡(jiǎn)介:2022年 博客新星 第八 。熱愛國(guó)學(xué)的Java后端開發(fā)者,修心和技術(shù)同步精進(jìn)。 ??個(gè)人主頁(yè):Java Fans的博客 ??個(gè)人信條:不遷怒,不貳過。小知識(shí),大智慧。 ??當(dāng)前專欄:SpringBoot 框架從入門到精通 ?特色專欄:國(guó)學(xué)周更-心性養(yǎng)成之路 ??本文內(nèi)容:SpringBoot使用

    2023年04月09日
    瀏覽(20)
  • 【面試題24】你是如何使用Redis分布式鎖的

    本文已收錄于PHP全棧系列專欄:PHP面試專區(qū)。 計(jì)劃將全覆蓋PHP開發(fā)領(lǐng)域所有的面試題, 對(duì)標(biāo)資深工程師/架構(gòu)師序列 ,歡迎大家提前關(guān)注鎖定。 Redis分布式鎖是一種利用Redis實(shí)現(xiàn)的分布式鎖機(jī)制。它通過在共享的Redis實(shí)例上設(shè)置一個(gè)特定的鍵值對(duì)來實(shí)現(xiàn)對(duì)資源的互斥訪問。今

    2024年02月11日
    瀏覽(17)
  • 分布式鎖實(shí)現(xiàn)(mysql,以及redis)以及分布式的概念(續(xù))redsync包使用

    分布式鎖實(shí)現(xiàn)(mysql,以及redis)以及分布式的概念(續(xù))redsync包使用

    這張盡量結(jié)合上一章進(jìn)行使用:上一章 這章主要是講如何通過 redis 實(shí)現(xiàn)分布式鎖的 這里我用 redis 去實(shí)現(xiàn): 技術(shù): golang , redis , 數(shù)據(jù)結(jié)構(gòu) 這里是有一個(gè)大體的實(shí)現(xiàn)思路:主要是使用 redis 中這些語(yǔ)法 redis 命令說明: setnx 命令: set if not exists ,當(dāng)且僅當(dāng) key 不存在時(shí),將 ke

    2024年01月22日
    瀏覽(27)
  • XXL-JOB中間件【實(shí)現(xiàn)分布式任務(wù)調(diào)度】

    XXL-JOB中間件【實(shí)現(xiàn)分布式任務(wù)調(diào)度】

    目錄 1:XXL-JOB介紹 2:搭建XXL-JOB 2.1:調(diào)度中心 2.2:執(zhí)行器 2.3:執(zhí)行任務(wù) 3:分片廣播 XXL-JOB是一個(gè)輕量級(jí)分布式任務(wù)調(diào)度平臺(tái),其核心設(shè)計(jì)目標(biāo)是開發(fā)迅速、學(xué)習(xí)簡(jiǎn)單、輕量級(jí)、易擴(kuò)展。現(xiàn)已開放源代碼并接入多家公司線上產(chǎn)品線,開箱即用。 官網(wǎng):https://www.xuxueli.com/xxl-

    2024年02月03日
    瀏覽(20)
  • 使用 redis 實(shí)現(xiàn)分布式接口限流注解 RedisLimit

    使用 redis 實(shí)現(xiàn)分布式接口限流注解 RedisLimit

    前言 很多時(shí)候,由于種種不可描述的原因,我們需要針對(duì)單個(gè)接口實(shí)現(xiàn)接口限流,防止訪問次數(shù)過于頻繁。這里就用 redis+aop 實(shí)現(xiàn)一個(gè)限流接口注解 @RedisLimit 代碼 點(diǎn)擊查看RedisLimit注解代碼 AOP代碼 點(diǎn)擊查看aop代碼 lua腳本代碼 注意:腳本代碼是放在 resources 文件下的,它的類型是

    2024年02月08日
    瀏覽(23)
  • Zookeeper 和 Redis 哪種更好? 為什么使用分布式鎖? 1. 利用 Redis 提供的 第二種,基于 ZK 實(shí)現(xiàn)分布式鎖的落地方案 對(duì)于 redis 的分布式鎖而言,它有以下缺點(diǎn):

    關(guān)于這個(gè)問題,我們 可以從 3 個(gè)方面來說: 為什么使用分布式鎖? 使用分布式鎖的目的,是為了保證同一時(shí)間只有一個(gè) JVM 進(jìn)程可以對(duì)共享資源進(jìn)行操作。 根據(jù)鎖的用途可以細(xì)分為以下兩類: 允許多個(gè)客戶端操作共享資源,我們稱為共享鎖 這種鎖的一般是對(duì)共享資源具有

    2024年01月16日
    瀏覽(23)
  • 分布式鎖設(shè)計(jì)選型 不可重入鎖建議使用ZooKeeper來實(shí)現(xiàn) 可重入鎖建議使用Redis來實(shí)現(xiàn) 分布式鎖:ZooKeeper不可重入鎖 Java優(yōu)化建議

    在設(shè)計(jì)分布式鎖時(shí),需要考慮業(yè)務(wù)場(chǎng)景和業(yè)務(wù)需求,以保證鎖的正確性和可用性。 例如,在一個(gè)電商系統(tǒng)中,每個(gè)商品都有一個(gè)庫(kù)存量。為了避免多個(gè)用戶同時(shí)購(gòu)買同一件商品導(dǎo)致庫(kù)存出現(xiàn)不一致的情況,可以為每個(gè)商品設(shè)置一個(gè)分布式鎖,確保同一時(shí)間只能有一個(gè)用戶購(gòu)買

    2024年02月08日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包