面试题答案
一键面试基本原理
- SETNX命令:Redis 的
SETNX
(SET if Not eXists)命令用于在指定的键不存在时,设置键的值。当一个客户端执行SETNX lock_key value
时,如果lock_key
不存在,那么设置成功,返回1
,表示获取到锁;如果lock_key
已经存在,返回0
,表示获取锁失败。这里的value
可以是一个唯一标识,比如客户端生成的 UUID,用于后续解锁时验证。 - 设置过期时间:为了防止获取锁的客户端出现异常(如崩溃、网络故障等)而导致锁永远无法释放,需要给锁设置一个过期时间。可以在获取锁成功后,使用
EXPIRE
命令设置过期时间,或者在 Redis 2.6.12 及以上版本,直接在SET
命令中使用EX
选项设置过期时间,例如SET lock_key value EX 10 NX
,表示设置lock_key
的值为value
,过期时间为 10 秒,且只有在lock_key
不存在时才设置。
高并发场景下可能出现的问题及解决方法
- 锁过期问题
- 问题描述:假设一个客户端获取锁后,在处理业务逻辑过程中时间过长,超过了锁的过期时间,此时锁自动释放,其他客户端可以获取到锁。而原持有锁的客户端处理完业务逻辑后,再去释放锁,就可能误释放其他客户端的锁。
- 解决方法:
- 使用唯一标识:在获取锁时,每个客户端使用自己生成的唯一标识(如 UUID)作为
value
。在释放锁时,先验证当前锁的value
是否与自己的标识一致,只有一致时才执行释放操作。可以通过 Lua 脚本来保证验证和释放操作的原子性,例如:
- 使用唯一标识:在获取锁时,每个客户端使用自己生成的唯一标识(如 UUID)作为
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
- **延长锁的过期时间**:在业务逻辑执行过程中,通过定时任务(如使用 Redis 的 `EXPIRE` 命令)定期检查并延长锁的过期时间,确保在业务完成前锁不会过期。
2. 并发竞争问题
- 问题描述:在高并发场景下,多个客户端同时尝试获取锁,可能由于网络延迟等原因,导致多个客户端认为自己获取到了锁。
- 解决方法:
- 增加重试机制:获取锁失败的客户端,等待一段随机时间后重试获取锁,减少多个客户端同时竞争锁的概率。
- 使用 Redlock 算法:Redlock 算法通过使用多个独立的 Redis 实例来实现分布式锁。客户端需要在大多数(N/2 + 1,N 为 Redis 实例数)的实例上成功获取锁,才算真正获取到锁。这样可以在一定程度上避免单点故障和并发竞争问题,但 Redlock 算法实现相对复杂,对系统性能也有一定影响。
3. 主从复制问题
- 问题描述:在 Redis 主从复制架构中,当主节点获取锁后,还未来得及将锁的信息同步到从节点,主节点就发生故障,从节点晋升为主节点。此时新的主节点上没有锁的信息,其他客户端可以再次获取锁,导致锁的安全性被破坏。
- 解决方法:
- 使用 Redlock 算法:如前文所述,Redlock 算法通过多实例机制,可以在一定程度上缓解主从复制带来的问题。
- 使用 Redis 事务:将获取锁的操作放到 Redis 事务中执行,通过 MULTI
、EXEC
命令保证操作的原子性,确保锁在主从复制过程中的一致性。但这种方法在高并发场景下性能会有所下降。