分布式锁的实现场景
在平时的开发中,对于高并发的开发场景,我们不可避免要加锁进行处理,当然redis中也是不可避免的,下面是我总结出来的几种锁的场景
Redis分布式锁方案一
使用Redis实现分布式锁最简单的方案是在获取锁之前先查询一下以该锁为key对应的value存不存在,如果存在,则说明该锁被其他客户端获取了,否则的话就尝试获取锁,获取锁的方法很简单,只要以该锁为key,设置一个随机的值就行了。比如,我们现在有个秒杀的场景,并发量可能是3000,但是我们商品的库存数量是一定的,为了防止超卖,我们就需要在减库存的时候加上锁,当第一个请求过来的时候,先判断锁时候存在,不存在就加锁,然后去处理秒杀的业务,并且在处理完成的时候,释放锁,如果判断锁存在,就轮训等待锁被释放。
缺点
1、如果我们处理业务的时候报错了,那么加上的锁就不能及时被释放了,这时候我们需要加上一个异常的捕获,在finally的时候释放锁。
2、同时我们也要主要set写入key,是会出现覆盖操作的,我们要要注意使用setnx(只要锁被加上,后面的写入操作不会覆盖前面的写入)
2、但是,有可能我们在处理业务的时候,整个服务器碟机了,那么异常的捕获显眼是不管用了,这时候我们的这种设计显然是存在缺陷的。
Redis分布式锁方案二
上一节的方案缺点就是锁有时候没有办法释放,造成死锁。那么对于setnx我们应该怎样处理呢?
考虑一种情况,如果进程获得锁后,断开了与 Redis 的连接(可能是进程挂掉,或者网络中断),如果没有有效的释放锁的机制,那么其他进程都会处于一直等待的状态,即出现“死锁”。
上面在使用 SETNX 获得锁时,我们将键 lock.foo 的值设置为锁的有效时间,进程获得锁后,其他进程还会不断的检测锁是否已超时,如果超时,那么等待的进程也将有机会获得锁。
然而,锁超时时,我们不能简单地使用 DEL 命令删除键 lock.foo 以释放锁。考虑以下情况,进程P1已经首先获得了锁 lock.foo,然后进程P1挂掉了。进程P2,P3正在不断地检测锁是否已释放或者已超时,执行流程如下:
从上面的情况可以得知,在检测到锁超时后,进程不能直接简单地执行 DEL 删除键的操作以获得锁。
为了解决上述算法可能出现的多个进程同时获得锁的问题,我们再来看以下的算法。
我们同样假设进程P1已经首先获得了锁 lock.foo,然后进程P1挂掉了。接下来的情况:
GETSET lock.foo <current Unix timestamp + lock timeout + 1>
另外,值得注意的是,在进程释放锁,即执行 DEL lock.foo 操作前,需要先判断锁是否已超时。如果锁已超时,那么锁可能已由其他进程获得,这时直接执行 DEL lock.foo 操作会导致把其他进程已获得的锁释放掉。
缺点
1、其实这种方案还存在缺陷,我们知道对于锁设置过期的时间,虽然可以解决锁的及时释放,但是我们知道我们需要处理的业务场景的时间的不可控,可能网络动荡,我们原来0.01秒的业务现在就需要3秒钟,所以简单的对锁设置过期的时间,还是存在缺陷的。
Redis分布式锁方案三
那么对于方案二的场景的缺点我们应该怎么去处理呢?有一个简单的方法就是当给一个锁加上过期的时间的时候,我们另外开启一个线程,去监测业务处理的时间,如果锁额时间快到了,并且业务还没有执行完毕,就给锁的时间延长,实现自旋的加锁。
原文:https://www.cnblogs.com/ricklz/p/10810061.html