基于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代码快中删除锁。

posted @ 2021-02-28 23:04  恋人星  阅读(627)  评论(0编辑  收藏  举报