Redis的key可以作为
分布式锁
,下面我们介绍一下分布式锁的一些基本知识:
分布式场景下的同步问题
- 在单机系统下我们可以使用
synchrtonized
和lock
等同步机制实现同步 - 在多机分布式系统下,我们可以采用图中的一些同步方法;这里我们重点介绍Redis实现分布式锁的问题
分布锁的实现
分布式锁本质上要实现的目标就是在Redis里面占一个茅坑,当别的进程也要来占时,发现已经有人蹲在这里了,就只好放弃或者稍后再试
下面介绍如何获取锁,和释放锁,以及存在的一些问题
获取锁
- 本之上就是在
redis
上设置一个key
,如果一个客户端已经设置了这个key,其余的客户端就不能再设置这个key了,但是- 如果在执行的时候,往往需要为这个客户端设置的key设置一个
expire
时间,,这样即使中间出现异常也可以保证锁可以正常释放。(解决死锁的问题)
为了确保原子性,可以使用SET KEY EX 秒数 NX
这里利用 Redis set key 时的一个 NX 参数可以保证在这个 key 不存在的情况下写入成功。并且再加上 EX 参数可以让该 key 在超时之后自动删除。
删除锁
在获取锁的进程执行完成之后,可以删除锁
del key
,但是这里往往存在一个问题,
若客户端1设置的key的expire时间到,但是由于客户端执行一个耗时时间长的操作,客户端2可以获取到锁,当客户端1执行完成之后,del key
,此时客户端2往往受到影响
为了解决这个问题,在删除的时候需要带上`key对应的value值,因此value值往往是一个随机数
//Lua脚本的方式确保原子性
public boolean releaseLock_with_lua(String key,String value) {
String luaScript = "if redis.call('get',KEYS[1]) == ARGV[1] then " +
"return redis.call('del',KEYS[1]) else return 0 end";
return jedis.eval(luaScript, Collections.singletonList(key), Collections.singletonList(value)).equals(1L);
}