Redis分布式鎖


原創轉載請注明出處:https://www.cnblogs.com/agilestyle/p/11605323.html

 

大部分開發人員利用Redis 實現分布式鎖的方式,都是使用SETNX+EXPIRE 組合來實現

這種方式實現的分布式鎖,是通過setnx 方法設置鎖,如果lockKey 存在,則返回失敗,否則返回成功。設置成功之后,為了能在完成同步代碼之后成功釋放鎖,方法中還需要使用expire 方法給lockKey 值設置一個過期時間,確認key值刪除,避免出現鎖無法釋放,導致下一個線程無法獲取到鎖,即死鎖問題。

如果程序在設置過期時間之前、設置鎖之后出現崩潰,此時如果lockKey 沒有設置過期時間,將會出現死鎖問題,這種問題的根源在於setnx 和expire 是兩條指令而不是原子指令。

在Redis2.8版本中,Redis的作者加入了set指令的擴展參數,使得setnx 和 expire 指令 可以一起執行。示例代碼如下:

RedisDistributedLock.java

 1 package org.fool.spring.util;
 2 
 3 import redis.clients.jedis.Jedis;
 4 
 5 public class RedisDistributedLock {
 6 
 7     private static final String LOCK_DEFAULT_FLAG = "true";
 8     private static final String LOCK_SUCCESS = "OK";
 9     private static final String SET_IF_NOT_EXIST = "NX";
10     private static final String SET_WITH_EXPIRE_TIME = "PX";
11 
12     private Jedis jedis;
13     private String lockKey;
14 
15     RedisDistributedLock(Jedis jedis, String lockKey) {
16         this.jedis = jedis;
17         this.lockKey = lockKey;
18     }
19 
20     /**
21      * 嘗試獲取分布式鎖
22      *
23      * @param expireTime 超期時間(ms)
24      * @return 是否獲取成功
25      */
26     public boolean tryLock(int expireTime) {
27         String result = jedis.set(lockKey, LOCK_DEFAULT_FLAG, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
28 
29         return LOCK_SUCCESS.equals(result);
30     }
31 
32     public void unlock() throws Exception {
33         jedis.del(lockKey);
34     }
35 
36     public boolean isAcquiredInThisProcess() {
37         String result = jedis.get(lockKey);
38 
39         return LOCK_DEFAULT_FLAG.equals(result);
40     }
41 
42 }

 

Test

執行第一次Test

在60s秒執行第二次Test,由於第一次Test還在執行中(即鎖還沒有釋放),導致沒有獲取到鎖

Note:

Redis的分布式鎖不能解決超時問題,如果在加鎖和釋放鎖之間的邏輯執行的時間太長,以至於超出了鎖的超時限制,就會出現超時問題。

因為這時候第一個線程持有的鎖過期了,臨界區的邏輯還沒有執行完,而同時第二個線程就提前重新持有了這把鎖,導致臨界區代碼不能得到嚴格串行執行。

為了避免這個問題,Redis分布式鎖不要用於較長時間的任務。

這個方案是目前最優的分布式鎖方案,但如果是在Redis集群環境下,依然存在問題。由於Redis集群數據同步到各個節點時是異步的,如果在Master節點獲取到鎖后,在沒有同步到其它節點時,Master節點崩潰了,此時新的Master節點依然可以獲取鎖,所以多個應用服務可以同時獲取到鎖。集群模式下推薦使用 Redisson

 

Reference

https://time.geekbang.org/column/article/125983

https://www.redis.net.cn/order/3552.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM