设计和构建具有大量重复任务的任务调度系统的好方法是啥?

Posted

技术标签:

【中文标题】设计和构建具有大量重复任务的任务调度系统的好方法是啥?【英文标题】:What is a good way to design and build a task scheduling system with lots of recurring tasks?设计和构建具有大量重复任务的任务调度系统的好方法是什么? 【发布时间】:2014-09-27 00:16:45 【问题描述】:

假设您正在构建类似于监控服务的东西,它有数千个任务需要在给定的时间间隔内执行,彼此独立。这可能是需要检查的单个服务器,或者需要验证的备份,或者只是可以安排在给定时间间隔运行的任何东西。

您不能只通过 cron 来安排任务,因为当任务运行时,它需要确定下一次应该何时运行。例如:

每 1 分钟安排一次服务器正常运行时间检查 第一次检查服务器已关闭,安排下一次检查在 5 秒后 5 秒后服务器再次可用,5 秒后再次检查 5 秒后服务器仍然可用,以 1 分钟间隔继续检查

想到的一个简单的解决方案是简单地让一个 worker 每秒运行一次左右,检查所有挂起的作业并执行需要执行的作业。但是,如果工作的数量是 100 000,这将如何运作?检查它们可能需要更长的时间,而不是工人的滴答间隔,并且任务越多,轮询间隔就越高。

有没有更好的方法来设计这样的系统?在实现这一点或处理此类问题的任何算法方面是否存在任何隐藏的挑战?

【问题讨论】:

我猜你应该调用低级操作系统函数来安排任务;他们可能最有效地在正确的时间调用它们。例如。 unixhelp.ed.ac.uk/CGI/man-cgi?at。除此之外,我可能会涉及队列和工作人员来管理可伸缩性。 处理 100000 个项目列表的时间不太可能超过 1 秒。您需要接近 10000000 的东西才能成为问题。此外,一旦您完成超过 86400 个任务,只需列出 86400 秒(一天中的秒数)并将您的任务附加到它们需要运行的秒数,效率会更高。 @slebetman:如果给定任务的下一次运行时间是明天的某个时间——或者第二天,或者从现在起一周后,这将如何工作?您是否会每天为下一年分配一个包含 86400 个项目的数组,只是为了安排每年恰好发生一次的“审计文件 xxx”? @JerryCoffin:没有提到运行时间会超过 24 小时。事实上,我最初阅读的规范允许您实现 1 小时的最大时间分辨率,这意味着您可能只使用 60 个插槽。 @slebetman:1 小时将是 3600 个插槽(不会有任何巨大差异)。 【参考方案1】:

使用优先级队列(优先级基于下一次执行时间)来保存要执行的任务。当您完成执行任务时,您会一直睡眠,直到队列最前面的任务时间。当一个任务到期时,你删除并执行它,然后(如果它是重复的)计算它下一次需要运行的时间,并根据它的下一次运行时间将它插入到优先级队列中。

这样,您在任何给定时间都有一个睡眠活动。插入和删除具有对数复杂性,因此即使您有数百万个任务,它也能保持高效(例如,插入具有一百万个任务的优先级队列在最坏的情况下应该需要大约 20 次比较)。

有一点可能有点棘手:如果执行线程一直等到特定时间才执行队列头部的项目,而您插入了一个新的项目到队列的头部,在之前存在的项目之前,您需要唤醒线程,以便它可以为现在位于队列头部的项目重新调整其睡眠时间。

【讨论】:

【参考方案2】:

我们在设计Revalee 时遇到了同样的问题,这是一个用于调度触发回调的开源项目。最后,我们最终编写了自己的优先级队列类(我们称之为ScheduledDictionary)来处理您在问题中概述的用例。作为一个免费的开源项目,完整的源代码(在本例中为 C#)可在GitHub 上获得。我建议你检查一下。

【讨论】:

以上是关于设计和构建具有大量重复任务的任务调度系统的好方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

宜信开源|分布式任务调度平台SIA-TASK的架构设计与运行流程

调度系统设计精要

用于调度代码重复运行的 Windows 任务调度程序有多可靠?

分布式任务调度架构原理和设计介绍

任务调度工具oozie和azkaban的对比

一天一门编程语言用 Go 语言实现一个 DAG 任务调度系统的API 接口代码