草庐IT

python - Python的分布式锁管理器

coder 2023-08-16 原文

我有一堆具有多个实例的服务器访问对每秒请求有硬性限制的资源。

我需要一种机制来锁定所有正在运行的服务器和实例对此资源的访问权限。

我在github上找到了一个restful分布式锁管理器:https://github.com/thefab/restful-distributed-lock-manager

不幸的是,似乎有一个分钟。锁定时间为 1 秒,相对不可靠。在多项测试中,解锁 1 秒锁需要 1 到 3 秒。

是否有经过良好测试的 python 接口(interface)可以用于此目的?

编辑:我需要能在 1 秒内自动解锁的东西。在我的代码中锁永远不会被释放。

最佳答案

我的第一个想法是使用 Redis。但是有更多很棒的工具,有些甚至更轻巧,所以我的解决方案建立在 zmq 之上。因此,您不必运行 Redis,运行小型 Python 脚本就足够了。

需求审查

在描述解决方案之前,让我先看看您的要求。

  • 限制在固定时间段内对某些资源的请求数。

  • 自动解锁

  • 资源(自动)解锁应在短于 1 秒的时间内发生。

  • 它应该被分发。我会假设,你的意思是多个分布式服务器消耗一些资源应该能够并且只有一个储物柜服务就可以了(更多关于它的结论)

概念

限制时间段内的请求数

时间段可以是一秒、更多秒或更短的时间。唯一的限制是 Python 中时间测量的精度。

如果您的资源有每秒定义的硬限制,您应该使用时隙 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()

运行你的服务器:

运行服务器.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

您将看到打印的“go”、“go”、“sorry”……响应。

尝试运行更多客户端。

一些压力测试

您可以先启动客户端,然后再启动服务器。客户端将阻塞,直到服务器启动,然后才会愉快地运行。

结论

  • 已满足所述要求
    • 请求数量有限
    • 无需解锁,只要有下一个可用时间段,它就会允许更多请求
    • LockerService 可通过网络或本地套接字使用。
  • 要可靠,zmq是成熟方案,python代码比较简单
  • 不需要所有参与者的时间同步
  • 表现会很好

另一方面,您可能会发现,您的资源限制并不像您假设的那样可预测,因此请准备好使用参数来找到适当的平衡,并始终为这方面的异常做好准备。

还有一些空间可以优化提供“锁”——例如如果储物柜用完了允许的请求,但当前时间段已经接近完成,您可以考虑稍等片刻,说“抱歉”,然后在几分之一秒后说“开始”。

将其扩展为真正的分布式锁管理器

通过“分布式”,我们还可以理解同时运行的多个储物柜服务器。这更难做到,但也是可能的。 zmq 允许非常容易地连接到多个 url,因此客户端可以真正轻松地连接到多个储物柜服务器。有一个问题,如何协调储物柜服务器不允许对您的资源有太多请求。 zmq 允许服务器间通信。一种模型可能是,每个储物柜服务器将在 PUB/SUB 上发布每个提供的“go”。所有其他储物柜服务器都将被订阅,并使用每个“go”来增加它们的本地请求计数器(逻辑略有修改)。

关于python - Python的分布式锁管理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23036990/

有关python - Python的分布式锁管理器的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  4. ruby - 分布式事务和队列,ruby,erlang,scala - 2

    我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和

  5. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  6. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  7. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  8. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  9. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  10. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

随机推荐