面试题答案
一键面试基本原理
- SETNX命令:Redis的
SETNX
(SET if Not eXists)命令用于在指定的键不存在时,设置键的值。在分布式锁场景中,多个客户端尝试使用SETNX
命令来设置同一个锁键。只有一个客户端能够成功设置,该客户端就获得了锁。例如:
SETNX lock_key unique_value
如果返回1,表示设置成功,获取到锁;返回0,表示锁已被其他客户端持有。
2. 唯一值标识:每个客户端在设置锁时使用一个唯一值(如UUID)作为锁的值。这是为了确保释放锁时,只能释放自己持有的锁,而不会误释放其他客户端的锁。
3. 过期时间:为了防止持有锁的客户端出现异常(如崩溃)而导致锁永远无法释放,需要为锁设置一个过期时间。可以在设置锁的同时通过EX
参数指定过期时间(单位为秒),例如:
SET lock_key unique_value EX 10 NX
上述命令表示在锁键不存在时设置锁键的值为unique_value
,并设置过期时间为10秒。
可能存在的问题及解决方案
- 锁的误释放
- 问题描述:当一个客户端A获取到锁并设置了过期时间,在执行任务过程中,由于某些原因(如网络延迟、GC停顿)导致执行时间过长,超过了锁的过期时间,锁自动释放。此时另一个客户端B获取到锁,而客户端A执行完任务后尝试释放锁,会误释放客户端B持有的锁。
- 解决方案:在释放锁时,通过Lua脚本来验证锁的唯一值。只有当锁的值与自己设置的唯一值相匹配时,才执行释放锁的操作。例如以下Lua脚本:
if redis.call("GET",KEYS[1]) == ARGV[1] then
return redis.call("DEL",KEYS[1])
else
return 0
end
在客户端中使用EVAL
命令执行该Lua脚本,将锁键作为KEYS[1]
,唯一值作为ARGV[1]
传入。
2. 锁的可靠性问题(主从复制场景)
- 问题描述:在Redis主从复制架构中,当主节点接收到客户端设置锁的命令后,还未来得及将锁的设置同步到从节点,主节点发生故障,从节点晋升为主节点。此时新的主节点上不存在锁,其他客户端可以再次获取锁,导致锁的可靠性被破坏。
- 解决方案:
- Redlock算法:使用多个独立的Redis实例(至少5个),客户端在大部分实例(至少3个)上成功设置锁才算获取到锁。释放锁时需要在所有实例上释放。具体步骤如下:
1. 获取当前时间(毫秒)。
2. 按顺序尝试在每个Redis实例上设置锁,设置时带上相同的唯一值和较短的过期时间(如50毫秒)。
3. 如果在超过半数(N/2 + 1,N为Redis实例个数)的实例上成功设置锁,且从开始设置锁到最后一个设置成功的总时间小于锁的过期时间,则认为获取到锁。
4. 如果获取锁失败,在所有实例上释放锁。
- Redisson框架:Redisson是一个基于Redis的Java驻内存数据网格(In-Memory Data Grid),它对分布式锁进行了封装,内部采用了Redlock算法,并提供了更易用的API,可有效解决锁在主从复制场景下的可靠性问题。