环境:python3
实现原理:WATCH, MULTI, EXEC, DISCARD事务机制实现分布式锁
MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务的基础。
事务可以一次执行多个命令, 并且带有以下两个重要的保证:
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
EXEC 命令负责触发并执行事务中的所有命令:
import uuid
import redis
import time
redis_client=redis.Redis(host='localhost', port=6379)
# 获取一个分布式锁
def acquire_lock(lock_name, acquire_time=10, time_out=10):
# 生成唯一id
identifier = str(uuid.uuid4())
# 客户端获取锁的结束时间
end = time.time() + acquire_time
# key
lock_names = "lock_name:" + lock_name
while time.time() < end:
# setnx(key,value) 只有key不存在情况下,将key的值设置为value,若key存在则不做任何动作,返回True和False
if redis_client.setnx(lock_names, identifier):
# 设置键的过期时间,过期自动剔除,释放锁
redis_client.expire(lock_names, time_out)
return identifier
# 当锁未被设置过期时间时,重新设置其过期时间
elif redis_client.ttl(lock_names)==-1:
redis_client.expire(lock_names, time_out)
time.sleep(0.001)
return False
# 锁的释放
def release_lock(lock_name, identifire):
lock_names = "lock_name:" + lock_name
pipe = redis_client.pipeline(True)
while True:
try:
# 通过watch命令监视某个键,当该键未被其他客户端修改值时,事务成功执行。当事务运行过程中,发现该值被其他客户端更新了值,任务失败
pipe.watch(lock_names)
if pipe.get(lock_names) == identifire: # 检查客户端是否仍然持有该锁
# multi命令用于开启一个事务,它总是返回ok
# multi执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC 命令被调用时, 所有队列中的命令才会被执行
pipe.multi()
# 删除键,释放锁
pipe.delete(lock_names)
# execute命令负责触发并执行事务中的所有命令
pipe.execute()
return True
pipe.unwatch()
break
except redis.exceptions.WatchError:
# # 释放锁期间,有其他客户端改变了键值对,锁释放失败,进行循环
pass
return False