Redis实现分布式锁

分布式环境下各个主机竞争统一资源时,传统的synchronize、ReentrankLock已不能满足要求。利用redis可以方便的实现分布式锁。
分布式锁要满足如下四个条件:

  • 1、互斥性 – 同一时间只有一方可以获得锁
  • 2、安全性 – 释放锁时不能影响其他方获得的锁,即只能释放自己获得的锁。
  • 3、死锁 – 避免获得锁的一方由于宕机而一直占用锁无法释放。
  • 4、容错 – 及时redis某些节点宕机,调用方依然能够获取或者释放锁。

1 获取锁

本质上是利用redis提供的setnx原子操作方法,

setnx key vlaue

如果key存在,则不设置value并返回0,否则设置key值为value并返回1。
为了防止获取锁的进程宕机而发生死锁,需要为redis指定一个超时时间

expire key 10

但此方法实现获取锁分为两步,先获取锁然后为锁指定超时时间,如果在获取锁后,调用进程宕机,则会导致锁无法释放,因此需要(setnx+expire)合二为一的原子操作方法。最新的redis版本已经提供了这个原子方法:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX] 
SET name "hello" EX 10086 NX

EX表示过期时间为秒,NX表示使用setnx 方法设置key。

java实现:

public String getRedisLock(Jedis jedis, String lockKey, Long timeOut) {
        try { 
        	// 定义锁的唯一标识,用于释放琐时判断是否是当前锁,用于保证安全性
            String uuid = UUID.randomUUID().toString();
            if ("OK".equals(jedis.set(lockKey, lockKey, "NX", "PX", timeOut))) {
           		return uuid;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

2 释放锁

释放锁分为两步:

  1. 判断获取锁时的uuid是否与redis中存的value值是否相等,相等则进行下一步
  2. 删除key

两步共同保证安全性,防止由于当前进程阻塞导致锁过期,另一个线程获取锁后更新了redis中的value值,当前进程醒来后不会删除掉最新的key。
但是前提是两步必须依然是原子操作,否则若在进行到第一步结束第二步未开始时,当前进程阻塞导致锁过期,其他进程获取锁,此时当前进程执行第二步依然会删除其他进程的锁。要想实现原子操作,需要借助lua脚本,如下:

public void unRedisLock(Jedis jedis, String lockKey, String value) {
        try {
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Integer result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(value));
            //0释放锁失败。1释放成功
            if (1 == result) {
            //如果你想返回删除成功还是失败,可以在这里返回
                System.out.println(result + "释放锁成功");
            }
            if (0 == result) {
                System.out.println(result + "释放锁失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

上述脚本会以原子形式被执行,lockKey和value会替换掉KEYS[1]) 和ARGV[1],最终返回的结果为脚本执行结果。

以上就是redis实现分布式锁的过程,至于容错性的保证,可以借助redis-cluster实现,这就是另外一个话题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值