1.为什么要有分布式锁?

在单机环境下,多个线程去访问共享资源,要保证线程安全,可以在代码块上加上synchronized或lock锁。

但是在多机器或者是分布式微服务架构下,synchronized锁和lock会失效,它只能保证单个jvm内部多个线程之间的互斥,而没有办法让集群下的多个jvm进程之间互斥。所以我们需要分布式锁,满足集群模式下多进程可见(让多个jvm进程都看到同一个锁监视器)并且互斥的锁,同时还要保证这个锁的高可用,高性能以及安全性。

2.实现分布式锁

实现分布式锁的核心是实现多进程之间互斥。常见的有三种方案:

1.MySQL

2.Redis

3.Zookeeper

Redis实现分布式锁

Redis可以利用setnx这样的互斥命令来实现锁。如果插入key成功,则表示获得到了锁,如果有人插入成功,其他人插入失败则表示无法获得到锁。释放锁就是将这条key删除。

同时考虑到安全性,如果这条锁还没来得及删除,服务宕机,那么这个锁将会永远存在,其它人也拿不到锁,这样会产生死锁问题。我们可以在setnx获取锁时,同时给它加一个过期时间,将来一旦服务出现故障,没有手动释放,到期以后,锁也会自动释放。

但是自动释放锁会出现误删别人锁的情况。假设业务阻塞,锁超时释放。这时其它线程获取到锁,还没有执行完,前面这个线程突然恢复运行,将该线程的锁释放掉。

针对这种情况,可以给锁加一个唯一标识(可以用线程id),在进行删除锁的时候,先进行判断,如果这个锁是自己的再删,如果不是,执行失败。同时还要保证查询唯一标识和删除锁是一个原子操作,否则依然会有安全问题。

可以使用lua脚本保证多条命令的原子性。

锁的超时时间设置多长?

太长:无效等待时间太多

太短:业务还没执行完

设置时间:比实际业务执行时间长一点。