MST

星途 面试题库

面试题:分布式系统中基于Redis实现分布式锁的原理

请阐述在分布式系统里,利用Redis实现分布式锁的基本原理,并且说明在高并发场景下可能会出现的问题及如何解决。
26.5万 热度难度
后端开发分布式系统

知识考点

AI 面试

面试题答案

一键面试

基本原理

  1. SETNX命令:Redis 的 SETNX(SET if Not eXists)命令用于在指定的键不存在时,设置键的值。当一个客户端执行 SETNX lock_key value 时,如果 lock_key 不存在,那么设置成功,返回 1,表示获取到锁;如果 lock_key 已经存在,返回 0,表示获取锁失败。这里的 value 可以是一个唯一标识,比如客户端生成的 UUID,用于后续解锁时验证。
  2. 设置过期时间:为了防止获取锁的客户端出现异常(如崩溃、网络故障等)而导致锁永远无法释放,需要给锁设置一个过期时间。可以在获取锁成功后,使用 EXPIRE 命令设置过期时间,或者在 Redis 2.6.12 及以上版本,直接在 SET 命令中使用 EX 选项设置过期时间,例如 SET lock_key value EX 10 NX,表示设置 lock_key 的值为 value,过期时间为 10 秒,且只有在 lock_key 不存在时才设置。

高并发场景下可能出现的问题及解决方法

  1. 锁过期问题
    • 问题描述:假设一个客户端获取锁后,在处理业务逻辑过程中时间过长,超过了锁的过期时间,此时锁自动释放,其他客户端可以获取到锁。而原持有锁的客户端处理完业务逻辑后,再去释放锁,就可能误释放其他客户端的锁。
    • 解决方法
      • 使用唯一标识:在获取锁时,每个客户端使用自己生成的唯一标识(如 UUID)作为 value。在释放锁时,先验证当前锁的 value 是否与自己的标识一致,只有一致时才执行释放操作。可以通过 Lua 脚本来保证验证和释放操作的原子性,例如:
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 事务中执行,通过 MULTIEXEC 命令保证操作的原子性,确保锁在主从复制过程中的一致性。但这种方法在高并发场景下性能会有所下降。