基于redis的分布式
# 分布式锁的关键点
- 互斥性: 任何时间内都只有一个线程获取锁
- 防死锁: 假如程序崩溃了没有是否锁,要有另外一种方式去释放锁
- 加锁和解锁必须是同一个线程
- 锁的续期问题
# 基于Redis的实现方案
# 互斥性
实现方式一 : Redis 的
set NX
方式,key不存在设置成功,key存在则设置失败,通过这种方式可以保证同一时间只要一个线程能设置成功。实现方式二:lua脚本的方式时间
# 如果key不存在,还没有客户端加锁
if ((redis.call('exists', KEYS[1]) == 0)
# 或者 hashKey(自己的clientId) 存在 , 说明自己获取锁
or (redis.call('hexists', KEYS[1], ARGV[2]) == 1)) then
# 通过 hincrby 的方式加锁, 如果是重入,则在原来的基础上+1
redis.call('hincrby', KEYS[1], ARGV[2], 1);
# 添加过期时间
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
# ttl获取剩余的过期时间
return redis.call('pttl', KEYS[1]);
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 防死锁
对lock_key
设置过期时间,Redisson设置的默认时间是 30s
.
# 加锁解锁同一个线程
redis中保存了 客户端线程,所以在解锁的时候可以去判断是否是自己加锁,只有时自己加锁才能去释放,避免误操作去释放锁
# 锁的续期问题
在实际的开发过程中,你很难去判断应该加锁多长时间,比如说你预估30s
,在当时可能这个时间是OK的,但是后面你加了新的业务逻辑,需要更长的时间,而你很有可能忘记了修改这个时间,那么这个超时时间就有问题了。
我们可以通过加个监听器去给锁增加时长,当key准备过期的时候,自动延长,这样就不会出现时间不够的情况,这也是Redisson目前时间的方案。
# 优点
- 与Zookeeper对比,性能比较高
- 通过Redisson的Watch Dog机制解决了锁的续约问题
- 锁可重入
- 锁申请等待资源,使用redis的消息订阅机制解决无效申请问题,减少了资源消耗
# 缺点
最大的缺点是: 如果使用Redis集群模式,当在master节点完成了加锁,此时master会同步给slave,假如此时master节点挂了,会导致锁信息丢失, slave切换成了master,其他线程就可以进来加锁,现象就是有多个线程同时获取锁,打破了互斥性
# 参考
上次更新: 2023/11/14, 14:12:09