我有一堆服务器,其中有多个实例,它们访问的资源对每秒的请求有很大的限制。
我需要一种机制来锁定所有正在运行的服务器和实例对此资源的访问。
我在github上找到了一个restful分布式锁管理器:https://github.com/thefab/restful-distributed-lock-manager
不幸的是似乎有一分钟。锁定时间为1秒,而且相对不可靠。在几个测试中,解锁1秒需要1到3秒。
我是否可以使用python接口对其进行很好的测试?
编辑:我需要在1秒内自动解锁的东西。锁永远不会在我的代码中释放。
发布于 2014-04-22 18:39:21
我的第一个想法是使用Redis。但是还有更好的工具,有些甚至更轻,所以我的解决方案构建在zmq之上。因此,您不必运行Redis,运行小型Python脚本就足够了。
需求审查
在描述解决方案之前,让我回顾一下您的需求。
概念
限制时隙内的请求数量
时隙可以是秒,更多的秒,或更短的时间。唯一的限制是Python中时间测量的精度。
如果资源具有每秒定义的硬限制,则应使用timeslot 1.0
监视每个时隙的请求数量,直到下一次开始。
对于访问资源的第一个请求,设置下一个时隙的开始时间并初始化请求计数器。
对于每个请求,增加请求计数器(针对当前时隙),并允许请求,除非您已经达到当前时隙中允许的最大请求数。
使用REQ/REP使用zmq服务
您的消费服务器可能会分布在更多的计算机上。要提供对LockerServer的访问,您将使用zmq。
样本代码
zmqlocker.py:
import time
import zmq
class Locker():
def __init__(self, max_requests=1, in_seconds=1.0):
self.max_requests = max_requests
self.in_seconds = in_seconds
self.requests = 0
now = time.time()
self.next_slot = now + in_seconds
def __iter__(self):
return self
def next(self):
now = time.time()
if now > self.next_slot:
self.requests = 0
self.next_slot = now + self.in_seconds
if self.requests < self.max_requests:
self.requests += 1
return "go"
else:
return "sorry"
class LockerServer():
def __init__(self, max_requests=1, in_seconds=1.0, url="tcp://*:7777"):
locker=Locker(max_requests, in_seconds)
cnt = zmq.Context()
sck = cnt.socket(zmq.REP)
sck.bind(url)
while True:
msg = sck.recv()
sck.send(locker.next())
class LockerClient():
def __init__(self, url="tcp://localhost:7777"):
cnt = zmq.Context()
self.sck = cnt.socket(zmq.REQ)
self.sck.connect(url)
def next(self):
self.sck.send("let me go")
return self.sck.recv()运行您的服务器:
run_server.py:
from zmqlocker import LockerServer
svr = LockerServer(max_requests=5, in_seconds=0.8)从命令行:
$ python run_server.py这将开始在本地主机上的默认端口7777上提供锁存器服务。
管理你的客户
run_client.py:
from zmqlocker import LockerClient
import time
locker_cli = LockerClient()
for i in xrange(100):
print time.time(), locker_cli.next()
time.sleep(0.1)从命令行:
$ python run_client.py你会看到“去”,“去”,“对不起”.打印答复。
试着运行更多的客户。
一点压力测试
您可以先启动客户端,然后启动服务器。客户端将阻塞,直到服务器启动,然后将愉快地运行。
结论
另一方面,您可能会发现,您的资源限制并不像您假设的那样可预测,所以要准备好使用参数来找到适当的平衡,并且总是为这方面的异常做好准备。
也有一些优化提供“锁”的空间--例如,如果储物柜用完了允许的请求,但是当前的时隙已经几乎完成,您可能会考虑用“对不起”等待一会儿,在第二次提供“开始”一小部分之后。
将其扩展到真正的分布式锁管理器。
通过“分布式”,我们也可以理解多个储物柜服务器一起运行。这是比较困难的,但也是可能的。zmq允许非常容易地连接到多个urls,因此客户端可以非常容易地连接到多个锁存服务器。有一个问题,如何协调储物柜服务器不允许太多的请求你的资源。zmq允许服务器间通信.一种模式可能是,每个储物柜服务器都会在PUB/SUB上发布每个提供的"go“。所有其他的锁存服务器都将被订阅,并使用每个"go“来增加它们的本地请求计数器(稍微修改了一些逻辑)。
发布于 2022-06-15 17:11:01
发布于 2014-04-23 23:54:52
对于我的集群,我将ZooKeeper与python库一起用于队列和锁。
为您的目的从kazoo api文档中修改的示例:http://kazoo.readthedocs.org/en/latest/api/recipe/lock.html
zk = KazooClient()
lock = zk.Lock("/lockpath", "my-identifier")
if lock.acquire(timeout=1):
code here
lock.release()但我记得,ZooKeeper至少需要三个节点。
https://stackoverflow.com/questions/23036990
复制相似问题