Redis 实现分布式锁的手段

106 阅读2分钟

Redis 可以用作实现分布式锁的一种手段,其基础是利用Redis的特性来保证锁的唯一性和原子操作。下面是常见的分布式锁实现方式:

1. 基于SetNX命令的分布式锁

SETNX 命令在指定的键不存在时,为该键设置值,如果键已经存在,则不做任何操作。


import redis

r = redis.Redis(host='localhost', port=6379, db=0)

lock_key = 'my_distributed_lock'

if r.set(lock_key, '1', nx=True, ex=30): # 设置过期时间为30秒

# 执行需要同步的代码

else:

print("无法获取锁")

这种方式简单但存在问题,比如获取锁的客户端崩溃或者网络问题导致Redis key丢失,这时锁就会被永久占用。

2. 基于SET命令的分布式锁

使用SET命令结合NXPX参数来设置锁,其中NX表示如果键不存在才设置,PX是指定键的过期时间。


import redis

import time

r = redis.Redis(host='localhost', port=6379, db=0)

lock_key = 'my_distributed_lock'

try:

# 尝试获取锁

if r.set(lock_key, '1', nx=True, px=30000):

# 执行业务逻辑

time.sleep(20) # 假设业务逻辑执行需要20秒

finally:

# 业务逻辑执行完成后释放锁

r.delete(lock_key)

这种方式相比第一种更安全,即使获取锁的客户端崩溃,锁也会在设定的过期时间后自动释放。

3. 基于Lua脚本的分布式锁

为了防止在释放锁时发生并发问题,可以使用Lua脚本来确保释放操作的原子性。


-- Lua脚本

local lock_key = "my_distributed_lock"

if redis.call("set", lock_key, "1", "nx", "px", 30000) then

return redis.call("get", lock_key)

else

return false

end


import redis

r = redis.Redis(host='localhost', port=6379, db=0)

lock_key = 'my_distributed_lock'

script = """

-- Lua脚本

local lock_key = "my_distributed_lock"

if redis.call("set", lock_key, "1", "nx", "px", 30000) then

return redis.call("get", lock_key)

else

return false

end

"""

# 执行业务逻辑

result = r.eval(script, 1)

if result:

# 执行业务逻辑

finally:

# 释放锁

r.eval(script, 1)

在使用Redis实现分布式锁时,需要注意:

  • 确保Redis服务的高可用和持久性。

  • 考虑锁的粒度,细粒度锁可能会导致更多的竞争和开销。

  • 注意业务逻辑的执行时间,避免锁过期后还未释放。

  • 在分布式系统中,网络分区和延迟是常态,设计时要考虑这些因素。

使用Redis实现分布式锁时,务必测试在不同场景下的行为,确保系统的稳定性和一致性。