目录
- 分布式锁
- Redis分布式锁
- setnx、expire
- 锁过期问题
- Redisson分布式锁
- Redisson加锁原理
- Redisson释放锁原理
- watch dog自动延期
- 分段锁
分布式锁
同一个JVM内部,往往采用synchronized或者Lock的方式来解决多线程间的安全问题。但是在分布式架构下,在JVM之间,那么就需要一种更加高级的锁机制,来处理种跨JVM进程之间的线程安全问题。这就用到分布式锁
Redis分布式锁
setnx、expire
原理解析
加锁问题
set同时设置过期时间命令
Redis使用Lua命令
Jedis操作分布式锁
springBoot项目直接引入
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
/**
* 尝试获取分布式锁
* @param jedis Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTime 超期时间
* @return 是否获取成功
*/
public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, long expireTime) {
//String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
String result = jedis.set(lockKey, requestId, SetParams.setParams().px(expireTime).nx());
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
/**
* 释放分布式锁
* @param jedis Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @return 是否释放成功
*/
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
锁过期问题
问题描述 STW问题引起
乐观锁解决方式
WatchDog自动延期
客户端1加锁的key默认生存时间30秒,如果超过了30秒,客户端1还想一直持有这把锁,咋办?只要客户端1一旦加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会没隔10秒检查一下,如果客户端1还持有锁key,那么就会不断延长锁key的生存时间
这种方式不会侵入业务代码,redisson就是采用这种方案
Redisson分布式锁
Redisson是基于Netty的Redis客户端。不但能操作原生的Redis数据结构,还为使用者提供了一系列具有分布式特性的常用工具类,实现了分布式锁。
Redisson分布式锁和JUC的Lock方法相似。RLock接口继承了Lock接口,锁的的结构是Hash,支持锁重入
Redisson加锁原理
加锁关键代码参考RedissonLock的tryLockInnerAsync方法
Redisson释放锁原理
释放锁关键代码参考RedissonLock的unlockInnerAsync方法
订阅Channel源码
watch dog自动延期
分段锁
分段锁原理