在分布式系统中,多个进程或服务可能会同时访问共享资源(如数据库、缓存、文件等),这可能会导致数据不一致或并发冲突。Redis 由于其高性能和单线程模型,是实现分布式锁的一个常见选择。本文将详细介绍使用 Redis 实现分布式锁的基本思路,包括 实现方式、锁的释放、可能存在的问题 以及 优化方案。
Redis 是一个高性能的内存数据库,具有 单线程执行命令 和 原子操作 的特点,因此可以用 SETNX
(SET if Not Exists
)等命令实现分布式锁。实现思路如下:
加锁
SET key value NX PX timeout
原子命令,确保只有一个客户端能成功设置锁,并带有超时时间。解锁
Lua
脚本保证检查锁值和删除锁的操作是原子的。超时自动释放
续租机制(可选)
使用 SET key value NX PX timeout
让多个客户端竞争锁:
SET lock_key random_value NX PX 5000 # 5秒过期时间
lock_key
:锁的唯一标识(如 "order:123:lock"
)。random_value
:每个客户端生成的唯一值,防止误删锁(UUID)。NX
:如果 key 不存在才设置(保证互斥性)。PX 5000
:超时 5000 毫秒,防止死锁。释放锁时,必须保证:
使用 Lua
脚本来确保“检查 + 删除”操作的原子性:
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
Redis 命令:
EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end" 1 lock_key random_value
设置 PX timeout
使 Redis 过期删除 key,避免死锁。
如果任务执行时间可能超过锁的超时时间,可以:
手动续租:
PEXPIRE lock_key timeout
续租。看门狗机制:
多个进程同时竞争锁时:
如果 Redis 运行在集群模式下,为了提高可用性,可以采用 RedLock 算法:
默认情况下,Redis 分布式锁 不是可重入的(即同一客户端多次 SETNX
会失败)。
解决方案:
hash
存储 计数器,同一个客户端多次加锁时递增计数,释放锁时递减:HSET lock_key owner random_value
HINCRBY lock_key counter 1
ZSET
)。import redis
import uuid
import time
class RedisLock:
def __init__(self, redis_client, lock_key, timeout=5):
self.redis = redis_client
self.lock_key = lock_key
self.value = str(uuid.uuid4()) # 生成唯一锁值
self.timeout = timeout # 过期时间(秒)
def acquire(self):
"""尝试获取锁"""
return self.redis.set(self.lock_key, self.value, nx=True, ex=self.timeout)
def release(self):
"""释放锁,使用 Lua 脚本确保原子性"""
lua_script = """
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
"""
return self.redis.eval(lua_script, 1, self.lock_key, self.value)
# 示例使用
redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)
lock = RedisLock(redis_client, "my_lock", timeout=5)
if lock.acquire():
print("锁获取成功")
time.sleep(3) # 模拟任务
lock.release()
else:
print("锁获取失败")
需求 | 方案 |
---|---|
互斥性 | SET lock_key value NX PX timeout |
可靠释放 | Lua 脚本 GET + DEL 原子操作 |
超时防死锁 | PX timeout 过期 |
续租机制 | PEXPIRE 或 看门狗 |
集群支持 | RedLock 算法 |
可重入性 | 计数器 + HSET |
共享锁 | ZSET 实现 |
Redis 分布式锁适用于高性能分布式系统,但也有缺点:
你可以根据实际业务需求,选择合适的实现方式 。