高并发场景下的redis分布式锁失效-Timer线程解决推荐redisson框架完美解决
1.建立一把redis分布式下的超时锁
Boolean result=StringRedisTemplate.opsForValue().setIfAbsent(lockKey,“value1”,10,TimeUnit.SECOND);
if(!result)
{return “error”;
}
问题1:如果业务执行的时间超过了锁的时间,出现锁失效的问题–第一个进程进来执行业务时候,锁突然超时了,这时候第二个业务进来了,此时第一个释放锁的时候释放的是第二个进程的锁,依次类推。。。
解决方法:创建一个客户端的识别的锁
String clientID=UUID.randomUUID().toString();
Boolean result=StringRedisTemplate.opsForValue().setIfAbsent(lockKey,clientID,10,TimeUnit.SECOND);
try{}
finally
{
if(clientID.equals(stringRedisTemplate().opsForValue().get(lockKey)))
{stringRedisTemplate.delete(lockKey)
}
}
问题2:
以上解决方法在高并发场景下会出问题,比如锁定超时60s,用户体验不行。
解决方法:利用timer给锁的超时时间续命(起一个分线程),比如隔10s,重新设置这把锁的超时时间
推荐redisson框架来实现(上述分线程的解决方法,redisson中利用类似timer操作防止死锁,redisson还可实现可重入锁–同一个线程不用等待相同的线程释放锁可以直接拿到该锁)
String lockKey=“lockKey”;
RLock redissonLock = redisson.getLock(lockKey);
try
{
redissonLock.lock();
业务代码;
}finally{
redissonLock.unlock();
}
问题3:如上图,如果再redis的master上设置完的锁后,突然宕机了,还没有往slave节点同步,怎么处理?
问题4:
redissonLock.lock(); 这个锁其实把请求变成了串行执行了,尽管redis的qps再高性能的服务器上能达到10万的qps,但是如果想更大的并发量提升个几十倍?
下图即解决问题3和问题4,其中问题3,如果不是非要用redis来做的话,还可以用zookeeper来保证主从的leader特性来保证同步性。但是性能不如redis好。如果非要用redis则用下图的redlock(不推荐使用redlock,还有写bug,如果用的话借助redisson框架来实现redis的分布式锁)来解决问题3,强烈建议使用zookeeper来创建分布式锁,充分利用zookeeper的leader选举机制来保证master的高可用性