zoukankan      html  css  js  c++  java
  • 基于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代码快中删除锁。

  • 相关阅读:
    记一次lvs-tunnel模式的故障分析(7)
    Zabbix实战-简易教程(4)--Server端安装
    Zabbix实战-简易教程(3)--DB安装和表分区
    HDFS跨外部存储系统的多层级存储
    HDFS副本放置节点选择的优化
    HDFS副本放置节点选择的优化
    HDFS的新方向:Ozone对象存储
    HDFS的新方向:Ozone对象存储
    聊聊HDFS中的副本放置策略和磁盘选择策略间的选择“矛盾”
    聊聊HDFS中的副本放置策略和磁盘选择策略间的选择“矛盾”
  • 原文地址:https://www.cnblogs.com/ljstudy/p/14461131.html
Copyright © 2011-2022 走看看