springboot-redis-redisson分布式锁
比较:redis很明显优于zookeeper;就分布式锁实现的健壮性而言,zookeeper很明显优于redis。如何选择,取决于你的业务!
一、Redis分布式锁实现原理
简介
Redis的4种部署架构有:
- 单机模式;
- 主从模式;
- 哨兵模式;
- 集群模式;
Redlock分布式锁在非单机模式下才有意义,单机模式下可以直接使用普通分布式锁。
因为RedLock的实现完全基于普通分布式锁;
RedLock加锁过程: 向所有节点发送 set key value ex time nx指令,只要过半节点set成功,就认为加锁成功。
RedLock释放锁过程: 向所有节点发送del指令;
因为RedLock操作多个节点,所以效率略有下降;但避免了网络分区产生的多锁同时存在的情况;
1.普通分布式锁
// 构造redisson实现分布式锁必要的Config
Config config = new Config();
config.useSingleServer().setAddress("1.9.1.0:5379").setPassword("123").setDatabase(0);
// 构造RedissonClient
RedissonClient redissonClient = Redisson.create(config);
// 设置锁定资源名称
RLock disLock = redissonClient.getLock("DISLOCK");
boolean isLock;
try {
//尝试获取分布式锁
isLock = disLock.tryLock(500, 15000, TimeUnit.MILLISECONDS);
if (isLock) {
//TODO if get lock success, do something;
Thread.sleep(15000);
}
} catch (Exception e) {
} finally {
// 无论如何, 最后都要解锁
disLock.unlock();
}
通过代码可知,经过Redisson的封装,实现Redis分布式锁非常方便,我们再看一下Redis中的value是啥,和前文分析一样,hash结构,key就是资源名称,field就是UUID+threadId,value就是重入值,在分布式锁时,这个值为1(Redisson还可以实现重入锁,那么这个值就取决于重入次数了):
172.29.1.180:5379> hgetall DISLOCK
1) "01a6d806-d282-4715-9bec-f51b9aa98110:1"
2) "1"
2.哨兵模式
即sentinel模式,实现代码和单机模式几乎一样,唯一的不同就是Config的构造:
Config config = new Config();
config.useSentinelServers().addSentinelAddress(
"redis://127.0.0.1:26378","redis://127.0.0.1:26379", "redis://127.0.0.1:26380")
.setMasterName("mymaster")
.setPassword("a123456").setDatabase(0);
RedissonClient redissonClient = Redisson.create(config);
// 还可以getFairLock(), getReadWriteLock()
RLock redLock = redissonClient.getLock("REDLOCK_KEY");
boolean isLock;
try {
isLock = redLock.tryLock();
// 500ms拿不到锁, 就认为获取锁失败。10000ms即10s是锁失效时间。
isLock = redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS);
if (isLock) {
//TODO if get lock success, do something;
}
} catch (Exception e) {
} finally {
// 无论如何, 最后都要解锁
redLock.unlock();
}
3.集群模式
集群模式构造Config如下:
Config config = new Config();
config.useClusterServers().addNodeAddress(
"redis://127.0.0.1:6375","redis://127.0.0.1:6376", "redis://127.0.0.1:6377",
"redis://127.0.0.1:6378","redis://127.0.0.1:6379", "redis://127.0.0.1:6380")
.setPassword("123").setScanInterval(5000);
RedissonClient redissonClient = Redisson.create(config);
// 还可以getFairLock(), getReadWriteLock()
RLock redLock = redissonClient.getLock("REDLOCK_KEY");
boolean isLock;
try {
isLock = redLock.tryLock();
// 500ms拿不到锁, 就认为获取锁失败。10000ms即10s是锁失效时间。
isLock = redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS);
if (isLock) {
//TODO if get lock success, do something;
}
} catch (Exception e) {
} finally {
// 无论如何, 最后都要解锁
redLock.unlock();
}
如果是多个没有关系的redis单机之间使用RedLock来做分布式锁
可以直接将各个单机的锁组成一个锁:
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
唯一ID
实现分布式锁的一个非常重要的点就是set的value要具有唯一性,redisson的value是怎样保证value的唯一性呢?答案是UUID+threadId。入口在redissonClient.getLock(“REDLOCK_KEY”),源码在Redisson.java和RedissonLock.java中:
protected final UUID id = UUID.randomUUID();
String getLockName(long threadId) {
return id + ":" + threadId;
}
看门狗Watchdog
看门狗是客户端的行为,创建锁后每隔10秒帮你把key的超时时间设为30s这样的话,就算一直持有锁也不会出现key过期了,其他线程获取到锁的问题了。
lockWatchdogTimeout(监控锁的看门狗超时,单位:毫秒)
默认值:30000
监