亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Redis分布式鎖的超時(shí)問題及解決

 更新時(shí)間:2024年05月11日 09:43:22   作者:阿飛Sirx  
這篇文章主要介紹了Redis分布式鎖的超時(shí)問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Redis分布式鎖的超時(shí)

Redis的分布式鎖并不能解決超時(shí)問題,如果在加鎖和釋放鎖之間的邏輯執(zhí)行得太長,以至于超出了鎖的超時(shí)限制,就會(huì)出現(xiàn)問題,因?yàn)檫@時(shí)候第一個(gè)線程持有的鎖過期了,臨界區(qū)的邏輯還沒有執(zhí)行完,而同時(shí)第二個(gè)線程就提前持有了這把鎖,導(dǎo)致臨界區(qū)代碼不能得到嚴(yán)格串行執(zhí)行

為了避免這個(gè)問題,分布式鎖不要用于較長時(shí)間的任務(wù),如果真的偶爾出現(xiàn)了問題,造成的數(shù)據(jù)小錯(cuò)亂,可能需要人工介入解決

有一個(gè)稍微安全一點(diǎn)的方案,是將set指令的value參數(shù)設(shè)置為一個(gè)隨機(jī)數(shù),釋放鎖時(shí)先匹配隨機(jī)數(shù)是否一致,然后在刪除key,這是為了確保當(dāng)前線程占有的鎖不會(huì)被其他線程釋放,除非這個(gè)鎖是自動(dòng)超時(shí),但是匹配value,和刪除ke y不是一個(gè)原子操作,所以只是相對(duì)安全

分布式鎖失效問題

分布式鎖

1.1集群下的鎖失效問題

Synchronized中的重量級(jí)鎖,底層就是基于鎖監(jiān)視器(Monitor)來實(shí)現(xiàn)的。

簡單來說就是鎖對(duì)象頭會(huì)指向一個(gè)鎖監(jiān)視器,而在監(jiān)視器中則會(huì)記錄一些信息

比如:

  • _owner:持有鎖的線程
  • _recursions:鎖重入次數(shù)

因此每鎖一個(gè)對(duì)象。都會(huì)指向一個(gè)鎖監(jiān)視器,但是每個(gè)鎖監(jiān)視器同一時(shí)刻只能被一個(gè)線程持有,這樣再單機(jī)模式下,不同服務(wù)的JVM當(dāng)然不能通信,這樣就會(huì)出現(xiàn)鎖失效問題。所以在分布式環(huán)境下就不能使用Synchronized。所以分布式鎖一定要滿足多JVM都能訪問并且互斥的條件。

能滿足上述特征的組件有很多,因此實(shí)現(xiàn)分布式鎖的方式也非常多,例如:

  • 基于MySQL
  • 基于Redis
  • 基于Zookeeper
  • 基于ETCD

常見的最廣泛的應(yīng)用解決方式就是基于Redis實(shí)現(xiàn)的分布式鎖。

1.2.簡單分布式鎖

先來弄清原理,Redis的setnx命令是基于string操作的。

命令如下:

SETNX key value

當(dāng)且僅當(dāng)這個(gè)key不存在時(shí)setnx才能執(zhí)行成功,并且返回1,其它情況都會(huì)執(zhí)行失敗,并且返回0.我們就可以認(rèn)為返回值是1就是獲取鎖成功,返回值是0就是獲取鎖失敗,實(shí)現(xiàn)互斥效果。

當(dāng)業(yè)務(wù)執(zhí)行完成時(shí),我們只需要通過DEL key命令刪除這個(gè)即可釋放鎖。這個(gè)時(shí)候其它線程又可以再次獲取鎖(執(zhí)行setnx成功)了。

不過我們要考慮一種極端的場景。獲取成功后,還沒釋放鎖時(shí)突然宕機(jī),那么釋放鎖的動(dòng)作就不會(huì)被執(zhí)行這就出現(xiàn)了死鎖。

# 獲取鎖,并記錄持有鎖的線程
SETNX lock thread1
# 設(shè)置過期時(shí)間,避免死鎖
EXPIRE lock 20我們可以利用Redis的KEY過期時(shí)間機(jī)制,在獲取鎖時(shí)給鎖添加一個(gè)超時(shí)時(shí)間:    

但是這顯然是兩條獨(dú)立的命令,如果我執(zhí)行完setnx后宕機(jī),過期時(shí)間還未設(shè)置,死鎖問題又出現(xiàn)了!

為了保證兩條命令的原子性使用SET lock thread1 NX EX 20 就能保證原子性。對(duì)應(yīng)的api如下。

@RequiredArgsConstructor
public class RedisLock {
 
    private final String key;
    private final StringRedisTemplate redisTemplate;
 
    /**
     * 嘗試獲取鎖
     * @param leaseTime 鎖自動(dòng)釋放時(shí)間
     * @param unit 時(shí)間單位
     * @return 是否獲取成功,true:獲取鎖成功;false:獲取鎖失敗
     */
    public boolean tryLock(long leaseTime, TimeUnit unit){
        // 1.獲取線程名稱
        String value = Thread.currentThread().getName();
        // 2.獲取鎖
        Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value, leaseTime, unit);
        // 3.返回結(jié)果
        return BooleanUtils.isTrue(success);
    }
 
    /**
     * 釋放鎖
     */
    public void unlock(){
        redisTemplate.delete(key);
    }
}

1.3.分布式鎖的問題

1.3.1.鎖誤刪問題

第一個(gè)問題就是鎖誤刪問題,目前釋放鎖的操作是基于DEL,但是在極端情況下會(huì)出現(xiàn)問題。

假設(shè)場景,線程1獲取鎖成功完成執(zhí)行,準(zhǔn)備釋放鎖。

 但因?yàn)槟承┰驅(qū)е箩尫沛i的操作被阻塞,直到超時(shí)放鎖

 

這時(shí)因?yàn)榫€程1被超時(shí)釋放,所以線程2拿到了鎖。這時(shí)候線程1醒了,給線程2的鎖刪了。

但此時(shí)線程2還是在執(zhí)行中,線程3在來的時(shí)候就會(huì)認(rèn)為現(xiàn)在沒人拿鎖,于是多個(gè)線程再次并發(fā)執(zhí)行,并發(fā)安全就可能再出現(xiàn)。

為了解決這種場景,我們可以在刪除鎖之前判斷當(dāng)前鎖的中保存的是否是當(dāng)前線程標(biāo)示,如果不是則證明不是自己的鎖,則不刪除;如果鎖標(biāo)示是當(dāng)前線程,則可以刪除。

1.3.2.超時(shí)釋放問題

  • 加上了鎖標(biāo)識(shí)判斷。
  • 可以避免大多數(shù)場景下的鎖誤刪問題,但是還是有極端情況。
  • 比如我線程1那所執(zhí)行完并且判斷完掛了,直到超時(shí)放鎖。
  • 這樣線程2來的時(shí)候是可以獲取鎖的,線程2去執(zhí)行業(yè)務(wù)中,線程1醒了,因?yàn)橐呀?jīng)通過了校驗(yàn),我給你鎖刪了,又發(fā)生了鎖誤刪問題。

總結(jié)起來,根源就在于判斷鎖標(biāo)識(shí)和刪除鎖是兩個(gè)動(dòng)作,又不符合原子性了。

1.3.3分布式鎖的其他問題

  • 鎖的重入問題:同一個(gè)線程多次獲取鎖的場景,目前不支持,可能會(huì)導(dǎo)致死鎖
  • 鎖失敗的重試問題:獲取鎖失敗后要不要重試?目前是直接失敗,不支持重試
  • Redis主從的一致性問題:由于主從同步存在延遲,當(dāng)線程在主節(jié)點(diǎn)獲取鎖后,從節(jié)點(diǎn)可能未同步鎖信息。如果此時(shí)主宕機(jī),會(huì)出現(xiàn)鎖失效情況。此時(shí)會(huì)有其它線程也獲取鎖成功。從而出現(xiàn)并發(fā)安全問題。

對(duì)應(yīng)的解決方案也有,就是比較麻煩

  • 原子性問題:可以利用Redis的LUA腳本來編寫鎖操作,確保原子性
  • 超時(shí)問題:利用WatchDog(看門狗)機(jī)制,獲取鎖成功時(shí)開啟一個(gè)定時(shí)任務(wù),在鎖到期前自動(dòng)續(xù)期,避免超時(shí)釋放。而當(dāng)服務(wù)宕機(jī)后,WatchDog跟著停止運(yùn)行,不會(huì)導(dǎo)致死鎖。
  • 鎖重入問題:可以模擬Synchronized原理,放棄setnx,而是利用Redis的Hash結(jié)構(gòu)來記錄鎖的持有者以及重入次數(shù),獲取鎖時(shí)重入次數(shù)+1,釋放鎖是重入次數(shù)-1,次數(shù)為0則鎖刪除
  • 主從一致性問題:可以利用Redis官網(wǎng)推薦的RedLock機(jī)制來解決

我們自己手寫解決不僅繁瑣,而且實(shí)現(xiàn)起來耗費(fèi)時(shí)間,所以我們可以使用開源的框架來實(shí)現(xiàn)分布式鎖。其中比較完善的一個(gè)第三方組件就是Redisson 。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • caffeine_redis自定義二級(jí)緩存

    caffeine_redis自定義二級(jí)緩存

    這篇文章詳細(xì)介紹了caffeine_redis 自定義二級(jí)緩存,文中有相關(guān)的背景前提與出現(xiàn)的問題,感興趣的同學(xué)可以參考一下
    2023-04-04
  • Redis的Cluster集群搭建的實(shí)現(xiàn)步驟

    Redis的Cluster集群搭建的實(shí)現(xiàn)步驟

    本文檔只對(duì)Redis的Cluster集群做簡單的介紹,并沒有對(duì)分布式系統(tǒng)的所涉及到的概念做深入的探討。感興趣的小伙伴們可以參考一下
    2021-07-07
  • redis事務(wù)常用操作詳解

    redis事務(wù)常用操作詳解

    在本篇文章里小編給大家分享了關(guān)于redis事務(wù)常用操作的相關(guān)知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以跟著學(xué)習(xí)參考下。
    2019-07-07
  • Redis數(shù)據(jù)庫中實(shí)現(xiàn)分布式鎖的方法

    Redis數(shù)據(jù)庫中實(shí)現(xiàn)分布式鎖的方法

    這篇文章主要介紹了Redis數(shù)據(jù)庫中實(shí)現(xiàn)分布式鎖的方法,Redis是一個(gè)高性能的主存式數(shù)據(jù)庫,需要的朋友可以參考下
    2015-06-06
  • 淺談Redis變慢的原因及排查方法

    淺談Redis變慢的原因及排查方法

    本文主要介紹了淺談Redis變慢的原因及排查方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Redis超詳細(xì)分析分布式鎖

    Redis超詳細(xì)分析分布式鎖

    在單體應(yīng)用中,如果我們對(duì)共享數(shù)據(jù)不進(jìn)行加鎖操作,會(huì)出現(xiàn)數(shù)據(jù)一致性問題,我們的解決辦法通常是加鎖。下面我們一起聊聊使用redis來實(shí)現(xiàn)分布式鎖
    2022-07-07
  • 詳解Redis中的List類型

    詳解Redis中的List類型

    這篇文章主要介紹了Redis中的List類型,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • redis與memcached的區(qū)別_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    redis與memcached的區(qū)別_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Memcached是以LiveJurnal旗下Danga Interactive公司的Bard Fitzpatric為首開發(fā)的高性能分布式內(nèi)存緩存服務(wù)器。那么redis與memcached有什么區(qū)別呢?下面小編給大家介紹下redis與memcached的區(qū)別,感興趣的朋友參考下吧
    2017-08-08
  • Redis優(yōu)化經(jīng)驗(yàn)總結(jié)(必看篇)

    Redis優(yōu)化經(jīng)驗(yàn)總結(jié)(必看篇)

    下面小編就為大家?guī)硪黄猂edis優(yōu)化經(jīng)驗(yàn)總結(jié)(必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03
  • Redis 數(shù)據(jù)類型的詳解

    Redis 數(shù)據(jù)類型的詳解

    這篇文章主要介紹了Redis 數(shù)據(jù)類型的詳解的相關(guān)資料,支持五種數(shù)據(jù)類型,字符串,哈希,列表,集合及zset,需要的朋友可以參考下
    2017-08-08

最新評(píng)論