zoukankan      html  css  js  c++  java
  • redis实现分布式锁

    清理邮件的时候发现之前看的一篇关于redis分布式锁实现的文章有人回复- -当时随意扫了眼文章,为了防止发生死锁,思路是使用setnx设置value为本地时间,然后获取锁失败时读取value进行时间比对。。然后我回复了下。。多台应用服务器存在时间不同步的问题。。

    其实使用setnx时设置下redis过期时间简单方便,只是通常在应用程序内通过sdk做这项操作时由于赋值+设置过期不在同一原子性操作中。。所以很多人觉得不可行了。。那就直接使用lua脚本呗,简单方便,原子性操作,性能也OK。

    加锁:aquire_lock_with_timeout.lua

    if redis.call("exists",KEYS[1]) == 0 then
        local lockSrc = redis.call("setex",KEYS[1],unpack(ARGV))
        if lockSrc then
            return "1"
        end
            return "0"
    end
    return "-1"

    释放锁:release_lock.lua

    if redis.call("get",KEYS[1]) == ARGV[1] then
        local lockRelease = redis.call("del",KEYS[1])
            if lockRelease then
                return "1"
            end
                return "0"
    end
    return "-1"

    java为例,加载两个lua脚本,然后简单加锁,释放锁

      @Bean
        @Qualifier("lockScript")
        public RedisScript<Integer> acquireLockWithTimeout() {
            DefaultRedisScript redisScript = new DefaultRedisScript();
            redisScript.setLocation(new ClassPathResource("redis/acquire_lock_with_timeout.lua"));
            redisScript.setResultType(Integer.class);
            return redisScript;
        }
    
    
        @Bean
        @Qualifier("unLockScript")
        public RedisScript<Integer> releaseLock() {
            DefaultRedisScript redisScript = new DefaultRedisScript();
            redisScript.setLocation(new ClassPathResource("redis/release_lock.lua"));
            redisScript.setResultType(Integer.class);
            return redisScript;
        }
        private Integer acquireTimeout;//资源占有锁的时间 秒s
        private Integer acquireInterval;//尝试获取锁的时限 ms
        private Integer lockTime;//尝试获取锁的时间间隔 ms
        
        @Autowired
        private RedisTemplate redisTemplate;
        @Autowired
        @Qualifier("lockScript")
        private RedisScript<Integer> acquireLockWithTimeout;
        @Autowired
        @Qualifier("unLockScript")
        private RedisScript<Integer> releaseLock;
    
         
        public String tryLock(String lockKey) {
            String lockValue = UUID.randomUUID().toString();
            Long endTime = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < endTime) {
                Integer lockResult = (Integer) redisTemplate.execute(acquireLockWithTimeout, Collections.singletonList(lockKey), lockTime, lockValue);
                if (lockResult.equals(1)) {
                    return lockValue;
                } else {
                    try {
                        Thread.sleep(acquireInterval);
                    } catch (InterruptedException ex) {
                        continue;
                    }
                }
            }
            return "";
        }
     
        public boolean releaseLock(String lockKey, String lockValue) {
            Integer releaseResult = (Integer) redisTemplate.execute(releaseLock, Collections.singletonList(lockKey), lockValue);
            if (releaseResult.equals(1)) {
                return true;
            }
            return false;
        }

    当然java也有更复杂更丰富的组件 redisson

  • 相关阅读:
    c++ 存储连续性,作用域和链接性注意点
    函数模板的知识点总结
    c++ 左值引用的注意点
    VS2015如何在同一个解决方案下建立多个项目及多个项目之间的引用
    编译opencv4.1.0+tesseract5.0 的Realease x64版本遇见的问题解决
    逻辑化简-卡诺图
    从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 (转载)
    matlab绘图
    多个EXCEL文件合并成一个
    数学建模及机器学习算法(一):聚类-kmeans(Python及MATLAB实现,包括k值选取与聚类效果评估)
  • 原文地址:https://www.cnblogs.com/ylsforever/p/8462716.html
Copyright © 2011-2022 走看看