视频字幕
在分布式系统中,多个服务实例可能同时访问共享资源。为防止冲突,需要使用分布式锁来协调访问。Redis 是实现分布式锁的常用工具。
Redis 使用 SETNX 命令实现分布式锁。SETNX 表示 SET if Not eXists。当 key 不存在时,设置成功返回 1;当 key 存在时,设置失败返回 0。这样可以保证只有一个客户端能获得锁。
使用 SETNX 获得锁后,如何释放锁?最简单的方法是使用 DEL 命令直接删除 key。但这样存在一个问题:可能误删其他客户端的锁。需要确保只能删除自己的锁。
为解决释放锁的问题,可以使用 GETSET 命令。首先在 SETNX 时设置一个唯一标识。释放锁时,先使用 GETSET 设置一个新的唯一标识,再比较返回值确认锁的归属。如果返回值与自己的标识一致,则成功释放锁。
为防止客户端崩溃导致死锁,需要给锁设置过期时间。可以使用 EXPIRE 命令,或在 SETNX 时直接设置过期时间。这样即使客户端崩溃,锁也会在过期后自动释放,避免资源永久占用。
为提高分布式锁的可靠性,Redis 官方推荐 Redlock 算法。该算法通过部署多个独立 Redis 实例来实现。客户端依次尝试获取所有实例的锁,只有在大多数实例上成功获取锁时,才认为获得锁成功。这样可以避免单点故障,提高系统的可靠性。
在 Redlock 算法中,释放锁需要向所有实例发送释放命令。为了保证原子性,通常使用 Lua 脚本来实现。Lua 脚本会先比较锁的唯一标识,确认是自己的锁后再删除,避免释放其他客户端的锁。
在 Redis 2.6.12 及以上版本中,推荐使用 SET 命令实现分布式锁。该命令将 SETNX 和 EXPIRE 合并为一个原子操作,避免了两个命令之间的竞争条件。使用 SET lock_key uuidA EX 30 NX 命令,可以同时设置锁和过期时间。
Redis 分布式锁的实现要点包括:首先使用 SET 命令的 NX 和 EX 选项来保证原子性;其次设置唯一标识防止误删其他客户端的锁;然后使用 Lua 脚本保证释放锁的原子性;最后可以采用 Redlock 算法来提高分布式锁的可靠性。