我有一堆具有多个实例的服务器,这些实例访问的资源对每秒的请求有硬性限制。
我需要一种机制来锁定所有正在运行的服务器和实例对此资源的访问。
有我在github上找到的一个restful分布式锁管理器: https://github.com/thefab/restful-distributed-lock-manager
不幸的是,似乎有一分钟。锁定时间为1秒,比较不可靠。在几次测试中,解锁 1 秒的锁需要 1 到 3 秒的时间。
有没有经过充分测试的 Python 接口可以用于此目的?
编辑:我需要在 1 秒内自动解锁的东西第二。在我的代码中锁永远不会被释放。
可以使用 Redis 或 ZooKeeper 等外部存储系统来实现分布式锁。这些系统提供了低级基元,可用于构建可靠的分布式锁。
使用 Redis 实现分布式锁
import redis
import time
import uuid
class DistributedLock:
def __init__(self, redis_client, lock_key, timeout=1):
self.redis_client = redis_client
self.lock_key = lock_key
self.timeout = timeout
self.lock_value = str(uuid.uuid4())
def acquire(self):
"""
尝试获取锁。
如果在超时内获取锁,则返回 True,否则返回 False。
"""
end_time = time.time() + self.timeout
while time.time() < end_time:
if self.redis_client.setnx(self.lock_key, self.lock_value):
# 成功获取锁
self.redis_client.expire(self.lock_key, self.timeout)
return True
time.sleep(0.01)
return False
def release(self):
"""
释放锁。
仅当锁由当前实例持有时才释放锁。
"""
# 使用 Lua 脚本确保仅当值为预期值时才删除密钥
unlock_script = """
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
"""
self.redis_client.eval(unlock_script, 1, self.lock_key, self.lock_value)
# 示例用法
redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)
distributed_lock = DistributedLock(redis_client, 'my_resource_lock')
if distributed_lock.acquire():
try:
# 访问受保护的资源
print("获得了锁,访问受保护的资源...")
time.sleep(0.5) # 模拟处理时间
finally:
distributed_lock.release()
else:
print("无法获取锁,跳过...")
说明:
-
该代码使用 Redis 的
setnx
命令来尝试以原子方式设置一个密钥。如果该密钥尚不存在,则此命令将设置该密钥并返回 True,否则返回 False。 -
expire
命令用于设置密钥的超时时间,确保即使在获取锁的客户端崩溃的情况下该锁也会被释放。 -
在
release
方法中,使用 Lua 脚本确保仅当锁由当前实例持有(即,值为预期值)时才删除该锁。这可以防止客户端意外删除其他客户端获取的锁。 -
此实现提供了一个 1 秒的超时时间,确保如果在
acquire
方法中无法获取锁,该方法将在 1 秒后返回。可以根据需要调整此超时时间。
使用 ZooKeeper 实现分布式锁
还可以使用
kazoo
库在 Python 中使用 ZooKeeper 实现分布式锁。
from kazoo.client import KazooClient
from kazoo.recipe.lock import Lock
# 创建与 ZooKeeper 的连接
zk = KazooClient(hosts='localhost:2181')
zk.start()
# 创建锁对象
lock = Lock(zk, '/my_resource_lock')
# 尝试获取锁
if lock.acquire(timeout=1):
try:
# 访问受保护的资源
print("获得了锁,访问受保护的资源...")
time.sleep(0.5) # 模拟处理时间
finally:
lock.release()
else:
print("无法获取锁,跳过...")
# 关闭 ZooKeeper 连接
zk.stop()
说明:
-
该代码使用
kazoo.recipe.lock.Lock
类在 ZooKeeper 中创建一个锁。 -
acquire
方法尝试获取锁,并可选地采用超时参数。 -
release
方法释放锁。
这些是使用 Redis 和 ZooKeeper 在 Python 中实现分布式锁的一些方法。可以根据的特定需求和约束选择最适合的方法。
标签:python,python-2.7,locking,distributed-lock From: 23036990