2012-02-15 162 views
15

我正在寻找推荐的解决方案来解决celerybeat是芹菜/ rabbitmq部署的单点故障。通过搜索网络,我没有发现任何有意义的东西。解决celerybeat是单点故障

就我而言,每天一次定时调度程序启动一系列可能运行半天或更长时间的作业。由于只能有一个celerybeat实例,所以如果它或它运行的服务器发生了问题,关键作业将不会运行。

我希望已经有一个工作解决方案,因为我不能是唯一需要可靠(集群或类似)调度程序的人。如果我不需要,我不想诉诸某种数据库支持的调度程序。

回答

5

芹菜github回购存在一个问题。不知道他们是否正在努力。

作为解决方法,您可以为任务添加一个锁,以便一次只运行特定PeriodicTask的一个实例。

喜欢的东西:

if not cache.add('My-unique-lock-name', True, timeout=lock_timeout): 
    return 

搞清楚锁定超时是很好,很棘手。我们使用0.9 *任务run_every秒,如果不同的celerybeats会尝试在不同的时间运行它们。只是为了留下一些余量(例如,当芹菜稍微落后于一次计划时,那么它按计划会导致锁仍然活动)。

然后,您可以在所有机器上使用celerybeat实例。每个任务将为每个celerybeat实例排队,但只有一个任务会完成运行。

任务仍然遵循run_every这种方式 - 最坏的情况:任务将以0.9 * run_every速度运行。

这种情况下的一个问题是:如果任务在排定时间排队但未在预定时间处理(例如因为队列处理器不可用) - 则锁定可能放置在错误的时间,导致可能1个下一个任务无法运行。为了解决这个问题,你需要某种检测机制,无论任务是按时或多或少。

但是,在生产中使用时,这不应该是常见的情况。

另一种解决方案是将celerybeat调度器子类化并覆盖它的tick方法。然后在处理任务之前为每个滴答声添加一个锁。这确保了只有具有相同周期性任务的celerybeats才会多次排队同一个任务。每个勾号只有一个celerybeat(赢得比赛条件的人)将排队任务。在一个芹菜跳下去的时候,下一个跳动的另一个将赢得比赛。

这当然可以与第一个解决方案结合使用。

当然,对于这项工作,缓存后端需要为所有服务器进行复制和/或共享。

这是一个老问题,但我希望它可以帮助任何人。