使用redlock实现分布锁的过程
SET key_name my_random_value NX PX 30000 NX 表示if not exist 就设置并返回true,否则不设置并返回false PX 表示过期时间用毫秒级,30000 表示这些毫秒时间后此key过期 redis分布式锁 有缺点: 只作用在一个redis节点上,即使redis通过sentinel 保证高可用性,但是如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失 在redis的master节点拿到了锁,但是这个加锁的key还没有同步到slave节点; master就故障了,发生故障后,slave节点称为master节点。导致锁丢失。
使用场景:
多个服务器间保证同一时刻同一时间段内同一个用户只能有一个请求
假如有5个完全独立的redis master服务器
- 1,获取当前时间戳
- 2,client尝试按照顺序以相同的key-value去获取redis服务的锁,在获取锁的过程中,获取时间要远小于锁的过期时间。这是为了防止长时间等待已经关闭的锁。并尝试获取下一个锁。
- 例如:TTL:是5s,设置获取锁的时间最多1s,所以一秒内无法获取锁,就放弃获取这个锁,并且尝试获取下一个redis实例。
- 3,client通过获取所有能获取的锁后的时间建议第一次记录的时间,这个时间差要小于TTL时间并且至少有3个redis的服务的锁被成功获取,才算真正的获取锁成功。
- 4,如果成功获得锁,则锁的正式有效时间就是TTL-(时间差)的时间。比如TTL:5s,获取3个锁以上的时间差是2s,则真真锁的有效时间就是3s,其实应该减去时钟漂移
- 5,如果由于某些原因,client获取锁失败。那么便会开始解锁所有的redis实例;因为有可能获取了小于(N/2+1) 个锁,所以要释放。不然影响其他client获取锁
最低保证分布式锁的有效性及安全性的要求
1,互斥:任何时刻只有一个client获取锁
2,释放死锁:即使锁定资源的服务崩溃或者分区,仍然要释放锁。设置了过期时间
3,容错性:只要多数redis节点(一半以上)在使用,client就可以获取和释放锁
概念描述:
TTL:redis key的过期时间或者有效生存时间
clock drift :时钟漂移;指两个电脑间时间流速基本相同的情况下,两个电脑时间差;
优点:
防止了单节点故障造成整个服务停止运行的情况。
在多节点中锁的设计,及多节点同时崩溃等各种意外情况有自己独特的设计方式
防止死锁
在分布式高并发的情况下,比如有个线程获得锁的同时,还没来得及去释放锁,就因为系统故障或者其他原因使它无法执行释放锁的命令,导致其他线程就无法获得锁。造成死锁
所以分布式要设置锁的“”“有效时间”“”,确保系统出现故障后,在一定时间内主动释放锁,避免造成死锁的情况
性能:
对于访问量大的共享资源,需要考虑减少锁等待的时间,避免大量线程阻塞
所以在设计锁的时候,要考虑两点
1,锁的颗粒度要尽量小:比如你要通过锁来减库存,那这个锁的名称你可以设置成商品ID,而不是任取名称,这样这个锁只对当前商品有效。锁的颗粒度小
2,锁的范围要小:比如要锁2行代码就可以解决问题,就不要锁10行代码
重入:
我们知道reentrantLock 可重入锁。特点:同一个线程可以拿到同一个资源的锁,重入锁非常有利于高效利用。
加锁的机制:
线程去获取锁,获取成功:执行lua脚本,保存数据到redis数据库
线程去获取锁,获取失败:while循环尝试一直获取锁,直到获取 成功,执行lua脚本,将数据保存到redis数据库
watch dog 自动延时机制
如果线程1 进来获取锁后,线程一切正常,但是它的业务逻辑需要执行2s,而锁的过期时间是1s
此时线程2 进来了,就会获取锁,此时,线程1,和线程2 就会同时执行逻辑代码,所以不合理
而且这种情况,释放锁的时候,会抛出异常。
这个时候,watchdog就出现了,他的作用就是保证线程1 业务还有没执行完,时间就过期了,如果线程1还想继续持有锁,进行业务处理那么启动一个wachdog后台线程,不断的延长锁的有效时间。
正常情况下watchdog是不默认启动的,而且启动会会对整体的性能产生一定的影响。
可重入锁的机制:
redis存储锁的数据类型是hash
hash数据类型的key值包含了当前线程信息

浙公网安备 33010602011771号