基於Redission框架實現redis 分布式鎖


1、起初

引入依賴

<!-- spring boot redis緩存引入 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

controller層

/**
 * @author lj on 2021/2/28.
 * @version 1.0
 */
public class IndexController {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestMapping("/test")
    public String testRedisDis(){
        final Boolean res = redisTemplate.opsForValue().setIfAbsent("lock_key", "liujun");
        if(!res){
            return "error";
        }
        /**
         * 執行代碼業務
         */
        return "end";
    }
}

思考?帶來一系列的問題:

1、系統宕機,未釋放鎖即死鎖(redis設置過期時間,增加try...finally...代碼段)

2、業務時間太長,釋放別人的鎖(設置redis值為唯一uuid;在釋放鎖時(redisTemplate.delete("key"),增加邏輯判斷只能釋放自己的鎖);增加看門狗來續時)

3、保證redis操作的原子性(redis設置值和設置過期時間必須同步)

2、進一步優化:

controller層

/**
 * @author lj on 2021/2/28.
 * @version 1.0
 */
public class IndexController {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestMapping("/test")
    public String testRedisDis(){
        String lock_key = "prodect_001";
        final String vaule = UUID.randomUUID().toString();
        try{
            final Boolean res = redisTemplate.opsForValue().setIfAbsent(lock_key, vaule,30, TimeUnit.SECONDS); //保證redis的原子性,設置時長防止redis死鎖
            if(!res){
                return "error";
            }
            //TODO 開辟一個分線程使用定時器進行redis續時
            /**
             * 執行代碼業務
             */
        }finally {
            //釋放鎖
            if(vaule.equals(redisTemplate.opsForValue().get(lock_key))){ //防止釋放別人的鎖
                redisTemplate.delete("lock_key");
            }
            return "end";
        }
    }
}

3、使用Redisson框架

1、引入Redisson的依賴

  <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.6.5</version>
        </dependency>

2、配置為單機模式

@Bean
    public Redisson redisson(){
        //此為單機模式
        final Config config = new Config();
        config.useSingleServer().setAddress("127.0.0.1:6379").setDatabase(0);
        return (Redisson) Redisson.create(config);
    }

3、簡單的使用代碼片段

 

 整個流程:

 

 

watch dog自動延期機制

客戶端1加鎖的鎖key默認生存時間才30秒,如果超過了30秒,客戶端1還想一直持有這把鎖,怎么辦呢?

簡單!只要客戶端1一旦加鎖成功,就會啟動一個watch dog看門狗,他是一個后台線程,會每隔10秒檢查一下,如果客戶端1還持有鎖key,那么就會不斷的延長鎖key的生存時間。

如果時集群的話還有一個問題:就是redis的master節點宕機了,而鎖沒來得及復制到slave節點(待處理。。。)

總結:redisson框架其實就是上面redis過程的優化;

先拿setnx來爭搶鎖,搶到之后,再用expire給鎖加一個過期時間防止鎖忘記了釋放;搶到鎖后會開辟一個分線程看門狗去續時,最后在finally代碼快中刪除鎖。


免責聲明!

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



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