【问题标题】:Asynchronous events to worker process for Django appDjango应用程序工作进程的异步事件
【发布时间】:2013-01-24 18:49:11
【问题描述】:

在我的 Django Web 应用程序中,我有一个工作程序,它是一个限速 API 的客户端,负责处理从我的服务器线程到该 API 的所有请求。我使用我的数据库来存储任务队列。任务可以大量出现,也可以根本没有。我正在使用事件循环来轮询队列并管理任务之间的延迟,以防超出速率限制(限制是动态的)。这一切都很好,但我唯一想做的另一件事是让工作人员在队列变干时停止访问数据库,以及让我的 Django 应用程序向工作人员发出队列不再存在的信号再次干燥。

从示意图上看,在伪 Python 中它看起来像这样:

state = NORMAL
delay_time = NORMAL_DELAY

while True:
    sleep(delay_time)

    if state == DORMANT:
        continue

    task = get_next_task() # hits database
    if task is None:
        state = DORMANT
        delay_time = NORMAL_TIME

    try:
        execute(task)
    except RateExceeded:
        delay_time = backoff(delay_time)
    else:
        delay_time = NORMAL_DELAY

# Triggered by web layer
def asynchronous_event():
    state = NORMAL

我要么想要一个从 Web 层触发的异步事件,该事件可以将状态设置回 NORMAL(将在 sleep 期间执行),要么想要一些不会添加不必要的循环数据库查询的其他轻量级检查。

在单机设置中,我可以只使用信号,但显然这在多机设置中不起作用。我试图不必仅仅为了这个信号而运行单独的消息队列服务器。我托管在 Dotcloud 上,以防万一基于网络的解决方案起作用。理想情况下,在易于实现方面或多或少等同于信号处理程序。我已经研究过 ZeroRPC,但我不确定如何将它合并到我的事件循环中。

有什么想法吗?

编辑

我正在研究 ZeroMQ 来解决这个问题,但我需要一些帮助。棘手的部分是会有多个并发的网络服务器实例,并且在重新部署时,我需要从一个工作人员平稳过渡到其继任者。所以,请耐心等待,因为我的术语可能不正确,在我看来,最好的办法是让每个工作人员异步绑定到作为邮箱的地址,在主循环中检查以从休眠模式唤醒.每个工作人员在其 IP 的数据库中创建一条记录,并带有创建日期的时间戳。提交请求时,Web 服务器会向所有工作人员发布消息。当一个worker接收到一条消息时,它会检查它的worker是否具有最新的创建日期:如果是,它会处理该消息,如果不是,它会自行终止。

这似乎很麻烦,但我想把它做好,因为我可能会在我的应用程序的其他地方使用这个范例。

【问题讨论】:

  • 如果您已经在使用 Redis,您可以将其用作轻量级队列。这会将它从数据库中一起删除,而且速度非常快。
  • 听起来不错,但我还没有使用 Redis。如果这是唯一不错的选择,我可能只好忍气吞声了。
  • 如果您正在查看 ZeroMQ 并且正在使用 Python,您应该查看 ZeroRPC。它有助于抽象出很多 ZeroMQ 复杂性。
  • 糟糕,刚刚注意到您已经查看了 ZeroRPC。很抱歉没有仔细关注。
  • 可能有一种方法,向 dotcloud 提交支持票证,这可能是获得答案的最佳选择。

标签: django asynchronous signals message-queue dotcloud


【解决方案1】:

如果数据库中没有任务,如何对工作作业的delay_time 应用指数退避?这可能会让您减少足够多的数据库负载,而无需将消息从 Web 应用程序传输到工作作业的额外复杂性。比如:

delay_time = NORMAL_DELAY

while True:
    sleep(delay_time)
    task = get_next_task() # hits database

    if task:
        try:
            execute(task)
        except RateExceeded:
            pass
        else:
            delay_time = NORMAL_DELAY
            continue

     delay_time = backoff(delay_time)

【讨论】:

  • 问题是我需要在有任务时快速响应
【解决方案2】:

事实证明,我决定每次循环都访问数据库。但我也决定,如果我想努力让这变得真正高效,ZeroMQ 是必经之路。以下是它的工作原理:

每个 worker 绑定一个 ZeroMQ 订阅套接字并将自己注册到 worker 数据库中,其中包含套接字的 IP 地址和端口。网络线程向最近注册的工作人员发布 DO_TASK 消息,向可能正在工作的任何其他人发布 QUIT 消息。

我在 Dotcloud 上进行部署,他们的支持说使用 custom service 环境变量和构建选项可以让我打开必要的端口并获取工作任务实例的 IP。

【讨论】:

    猜你喜欢
    • 2013-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多