重談redis分布式鎖

前言

Redis分布式鎖其實網(wǎng)上已經(jīng)一大把了拴孤,我寫這篇博客的目的是想發(fā)表下自己的淺見荧琼。

我們知道在單進程中,通過語言內(nèi)置的鎖可以保證數(shù)據(jù)的一致性带迟,隨著軟件的不斷擴大,很多應用已經(jīng)是多進程的方式部署,那么為了保證數(shù)據(jù)的一致性,我們需要一個分布式鎖囱桨。標題說的是Redis分布式鎖仓犬,那么我下面主要講的rendis鎖,而且不會涉及到redis單點故障的問題舍肠。

常見的分布鎖

搜索一下常見的分布式鎖說的都是通過redis和zookeeper來實現(xiàn)搀继。

  • redis

    setnx 通過設置一個共有的key,而且通過設置過期時間來避免死鎖

  • zk

    通過設置一個共有的節(jié)點,通過zk的watch,觀察節(jié)點的變化進行通知

鎖的需求

  • 獨占: 一個時間點只能一個線程訪問

  • 可重入: 同一個線程只要當前持有鎖翠语,可以重復進入

  • 避免死鎖: 多個線程訪問不會出現(xiàn)死鎖的情況

  • 鎖釋放: 進程故障能自動釋放鎖叽躯,只有持有鎖的進程能釋放鎖

嘗試自己實現(xiàn)一個

實現(xiàn) copy from importnew Redis 分布式鎖的正確實現(xiàn)方式( Java 版 )

public class RedisTool {
 
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
 
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
 
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
 
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
 
    }

    private static final Long RELEASE_SUCCESS = 1L;
 
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
 
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
 
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
 
    }
 
}

上面的鎖實現(xiàn)存在一個問題,假如程序員A不小心調(diào)用了releaseDistributedLock就會把某個已經(jīng)持有鎖的?線程的鎖釋放掉。相信大家都能想到用ThreadLocal方式避免給未持有鎖的線程釋放了肌括。 那我就試著將這代碼改改点骑。(偽代碼)

public class RedisToolv2 {

   private static final String LOCK_SUCCESS = "OK";
   private static final String SET_IF_NOT_EXIST = "NX";
   private static final String SET_WITH_EXPIRE_TIME = "PX";
   private final ThreadLocal<Boolean> hasLock = new ThreadLocal<>();

   public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

       String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
       
       boolean locked = false;

       if (LOCK_SUCCESS.equals(result)) {
           locked = true;
       }
       hasLock.set(locked);
       return locked;

   }

   private static final Long RELEASE_SUCCESS = 1L;

   public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
       boolean locked = Optional.ofNull(hasLock.get()).orElse(false) ;
       boolean unloked = false;
       if(locked){
           String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
           Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
           if (RELEASE_SUCCESS.equals(result)) {
               unloked = true;
           }
       }
       return false;
   }

}

上面的方式雖然說解決了其他線程誤刪鎖的情況,但是分布式鎖其實還有很多細節(jié)都地方需要實現(xiàn),當一個線程已經(jīng)擁有此鎖了畔况,如果還有大量其他(本應用或其他應用)的線程在請求鎖鲸鹦,無疑給redis造成很大的壓力(當然這個得看應用的規(guī)模,小規(guī)模是不會出現(xiàn)這個情況)跷跪。

假設我們同一個應用中同一個時間點只有線程在請求分布式鎖馋嗜,那么相對于Redis的壓力是不是就會下降很多? 那么我們在代碼中加入一個同步鎖是不是就解決了問題呢?首先我想到的是synchronized可以重入吵瞻,可以使用遞歸的方式調(diào)用葛菇。但是如果是遞歸,如果長時間拿不到鎖橡羞,那么有可能會引發(fā)StackOverflowError眯停。額, 那這不能實現(xiàn)卿泽,沒招了咩莺债? 其實jdk里面帶了一個 ReentrantLock,這個鎖其實跟synchronized差不多,也是可以重入的签夭,而且有一個 tryLock(long timeout, TimeUnit unit)的方法齐邦,在遞歸調(diào)用的時候可以避免Stack過大。 (思路有了第租,我相信代碼也是很輕易就寫出來了)

拋個磚

  • 那么這個鎖持有的時間該如何計算呢措拇?

  • 還有就是這么實現(xiàn)這個鎖是不是就完美了呢?慎宾?

  • Redis有個叫鍵空間通知(keyspace notification) 的功能丐吓,是不是可以用這種方式來實現(xiàn)一個類似zookeeper的鎖呢 ?

最后

各位看官還有什么好的思路歡迎來交流呀趟据。

博客

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末券犁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子之宿,更是在濱河造成了極大的恐慌族操,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件比被,死亡現(xiàn)場離奇詭異色难,居然都是意外死亡,警方通過查閱死者的電腦和手機等缀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門枷莉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尺迂,你說我怎么就攤上這事笤妙∶罢疲” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵蹲盘,是天一觀的道長股毫。 經(jīng)常有香客問我,道長召衔,這世上最難降的妖魔是什么铃诬? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮苍凛,結果婚禮上趣席,老公的妹妹穿的比我還像新娘。我一直安慰自己醇蝴,他們只是感情好宣肚,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悠栓,像睡著了一般霉涨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闸迷,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天嵌纲,我揣著相機與錄音,去河邊找鬼腥沽。 笑死,一個胖子當著我的面吹牛鸠蚪,可吹牛的內(nèi)容都是我干的今阳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼茅信,長吁一口氣:“原來是場噩夢啊……” “哼盾舌!你這毒婦竟也來了?” 一聲冷哼從身側響起蘸鲸,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤妖谴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后酌摇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膝舅,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年窑多,在試婚紗的時候發(fā)現(xiàn)自己被綠了仍稀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡埂息,死狀恐怖技潘,靈堂內(nèi)的尸體忽然破棺而出遥巴,到底是詐尸還是另有隱情,我是刑警寧澤享幽,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布铲掐,位于F島的核電站,受9級特大地震影響值桩,放射性物質發(fā)生泄漏迹炼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一颠毙、第九天 我趴在偏房一處隱蔽的房頂上張望斯入。 院中可真熱鬧,春花似錦蛀蜜、人聲如沸刻两。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磅摹。三九已至,卻和暖如春霎奢,著一層夾襖步出監(jiān)牢的瞬間户誓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工幕侠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帝美,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓晤硕,卻偏偏與公主長得像悼潭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子舞箍,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Java繼承關系初始化順序 父類的靜態(tài)變量-->父類的靜態(tài)代碼塊-->子類的靜態(tài)變量-->子類的靜態(tài)代碼快-->父...
    第六象限閱讀 2,157評論 0 9
  • 如果不去逛街的話,逛超市的話捎迫,人可能沒那么多不覺得有年味晃酒,可是今天在家里吃飯就感覺,什么是年味呢立砸?就是有長輩(...
    瘋癲飛閱讀 477評論 1 18
  • 2003年掖疮,致命病毒SARS爆發(fā)人們談SARS色變,不過這并沒有影響我們的JJ發(fā)行他的第一張專輯《樂行者》的大賣專...
    夏目心葉閱讀 1,514評論 10 11
  • 不知不覺都六點了颗祝,大家要么是在回家的路上浊闪,要么是已經(jīng)到家恼布,而悲催的我此刻還坐在辦公室里加班「楸觯看了一天的電腦折汞,忙到一...
    拆書家小強閱讀 787評論 5 5
  • 電視絕緣的我,今天無意瞥一眼電視盖腿,被女主人公那溫柔爽待、文雅、含蓄翩腐、秀美的姿態(tài)鸟款,高貴優(yōu)雅、雍容華貴所吸引茂卦,念念不忘何什!
    影半夏閱讀 182評論 0 1