是否使用过Redis分布式锁?它的工作原理是什么?

发布于 1周前 作者 yuanlaile 来自 问答

是否使用过Redis分布式锁?它的工作原理是什么?

1 回复

是否使用过Redis分布式锁?

是的,我使用过Redis来实现分布式锁。Redis分布式锁是解决在分布式系统中多个服务或实例对同一资源进行操作时,如何保证互斥访问的一种有效手段。

它的工作原理是什么?

Redis分布式锁的工作原理主要基于Redis的一些原子操作,如SETNX(SET if Not eXists,已在新版本中被SET命令配合条件参数取代)、EXPIRE(设置键的过期时间)等。但更常用的现代实践是使用Lua脚本来确保SETEXPIRE操作的原子性,或者使用Redis 2.6.12及以上版本中的SET命令的EX(设置键的过期时间,秒)、PX(设置键的过期时间,毫秒)选项。

示例代码(使用Redis命令)

传统方式(不推荐,因为非原子性)
# 尝试获取锁
SETNX lock_key unique_value
EXPIRE lock_key 10

# ... 业务逻辑

# 释放锁
DEL lock_key

注意:上面的代码存在竞态条件,因为SETNXEXPIRE是两个命令,不是原子的。

推荐方式(使用Lua脚本保证原子性)

在Redis中,你可以通过EVAL命令执行Lua脚本来实现原子操作:

-- Lua脚本
-- KEYS[1] 是锁的key,ARGV[1] 是锁的过期时间,ARGV[2] 是锁的标识(通常使用UUID)
if redis.call("setnx", KEYS[1], ARGV[2]) == 1 then
    redis.call("expire", KEYS[1], ARGV[1])
    return 1
else
    return 0
end

使用方式(在Redis客户端中):

EVAL "if redis.call('setnx', KEYS[1], ARGV[2]) == 1 then redis.call('expire', KEYS[1], ARGV[1]) return 1 else return 0 end" 1 lock_key 10 unique_value

这里EVAL命令的第一个参数是Lua脚本,第二个参数1表示脚本中KEYS数组的长度,后面跟着的是KEYS数组和ARGV数组的元素。

使用Redis命令的新特性

Redis 2.6.12及以上版本可以直接使用SET命令的EXPX选项来设置过期时间,从而简化操作:

SET lock_key unique_value EX 10 NX

这里NX参数确保只有在lock_key不存在时才设置键值对,与SETNX类似,但EX参数同时设置了键的过期时间,实现了操作的原子性。

注意事项

  • 确保锁的标识(unique_value)是唯一的,这有助于安全地释放锁,防止误解锁。
  • 在业务逻辑执行完毕后,无论成功或失败,都要释放锁。
  • 考虑到网络延迟、Redis服务宕机等异常情况,锁的实现可能需要更复杂的逻辑来确保最终一致性,如使用看门狗(Watchdog)机制。
回到顶部