首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >寻找高效的任务调度器

寻找高效的任务调度器
EN

Stack Overflow用户
提问于 2014-09-05 01:57:17
回答 5查看 338关注 0票数 0

我有几个工作,需要完成X次,我有不同的工人与他们自己的信息。

除此之外,作业有一个日期,我想在作业到达下一个作业之前处理它Y次,从最早的作业开始。

一个工人只能处理一个作业一次。

目前,我正在使用mysql数据库和php脚本来实现这一点,但是似乎在每秒50个作业的速度上存在瓶颈,我需要更快的速度,所以我必须寻找替代方案。

我的设置有以下表格:

代码语言:javascript
复制
jobs

job_id  | job_info  | last_processed    | times_executed    | to_be_done
1   | 949461321 | 05-04-2014 00:14:56   | 192               | 1000
2   | 356454214 | 05-04-2014 00:14:57   | 8                 | 200
3   | 321564642 | 05-04-2014 00:14:58   | 16                | 10000
4   | 546412131 | 05-04-2014 00:14:59   | 3                 | 50

workers 

worker_id   | specific_information  | status
1       | 4656439897543521456       | ok
2       | 6513165165465498498       | not_responsive
3       | 1046486479849870987       | not_responsive
4       | 6540498465494131131       | ok
5       | 6484654321654657498       | ok

除此之外,我还有以下设置(为了简单起见,这里使用pseudo_code ):

代码语言:javascript
复制
$jobs_per_run = 10; // Process 10 jobs when the script runs
$workers_per_run = 5; // Process each job 5 times before it moves to the next job

FOR $i = 0; $i < $jobs_per_run; $i++ {
    SQL_QUERY "SELECT * FROM jobs WHERE times_executed < to_be_done GROUP BY last_processed ASC"; // get least used job that needs processing
    FOR $j = 0; $j < $workers_per_run; $j++ {
        SQL_QUERY "SELECT * FROM workers WHERE status = 'ok' AND worker_id NOT IN($processed_workers)";
        IF job_was_executed_successfully {
            SQL_QUERY "UPDATE jobs SET times_executed = times_executed + 1, last_processed = NOW() WHERE job_id = $job_id";
        } else {
            SQL_QUERY "UPDATE workers SET status = 'not_responsive' WHERE worker_id = $worker_id"
        }
    }
}

我希望这能解释我所需要的。我甚至不知道这到底是怎么叫的。

我读过关于queuestask schedulersmessaging systems的文章,但这里的问题是,我需要由不同的工作者多次执行一个作业,这些工作者按last_processed排序。

我认为我前面提到的这些构造的工作原理就像你把一些作业放进去,然后它们就会一个接一个地被执行。使用我的设置,我想我需要从一开始就分配工人,然后例如将作业1/ 1000次分配给不同的工人。

这对我来说是个问题。有时工作进程并不总是可用的,如果我现在将工作进程1和作业2放在一起,如果它在几分钟内被执行,那么工作进程1就不会有响应。这就是为什么我现在在执行时分配一个工作的工人给一个作业。

task scheduler需要更易于管理,我需要能够暂停和恢复单个作业,并根据工作人员的“表行”中的不同标准选择它们。

我希望有活跃的300+工作者在队列系统上工作,而不会出现问题。一个worker在大约1秒内执行一个作业,因此这将是每秒完成的300+作业。

理想情况下,我希望有一个像Amazon AWS这样的云设置,其中我有一个实例作为任务调度器,还有几个其他实例来执行作业。

要达到这样的效果,最好的设置是什么?我现在拥有的mysql解决方案似乎是最方便、最合适的。也许有一个更快的数据库用于该作业,具有类似的功能?

EN

回答 5

Stack Overflow用户

发布于 2014-09-21 15:19:19

尽管我们的老师告诉我们,有这样一个愚蠢的问题;这就是为什么你到目前为止没有得到一个像样的答案。

这一次,我将花时间解释为什么这个问题是愚蠢的,希望未来的读者以及您自己都能从中受益,而不是忽略您提出的问题。

我希望300+工作人员在队列系统上积极工作,不会出现问题

这说明了一种误解;它表明您认为您的硬件能够并发执行300个线程,但这不是:我敢打赌,在我们有生之年不会有这样的硬件可供我们使用。

Multi-Threading in PHP with pthreads

有一种浪费的倾向;这是一个常见的误解,认为线程化任何东西都可以让它更快,但事实并非如此。更多的线程并不总是等同于更多的吞吐量,同样地,更多的水并不总是等同于更湿。

跳出框框思考是一个好的多线程程序员的先决条件;常识应该表明,更多的水确实意味着更湿,但如果你考虑一下碗底部的中心点:一旦它是湿的,无论你在上面放多少水,它都不会变得更湿……

水太多,线太多,你会被淹没的。

你应该阅读所有引用的文档,它应该让你很好地理解什么是可能的,以及如何实现的。

票数 6
EN

Stack Overflow用户

发布于 2014-09-09 23:33:23

关于您的查询,我注意到的一件事是,您选择了FOR循环中的所有记录。

不使用GROUP BY,而是使用ORDER by,因为我相信这就是您正在尝试做的事情,并限制查询本身中的作业数量:

代码语言:javascript
复制
SELECT * FROM jobs 
WHERE times_executed < to_be_done 
ORDER BY last_processed ASC LIMIT 10

由于作业只能由单个工作人员完成,因此您应该考虑使用LIMIT

代码语言:javascript
复制
SELECT * FROM workers 
WHERE status = 'ok' AND worker_id NOT IN($processed_workers) LIMIT 1

如果您计划将相同的工作分配给5个可用员工,则仍会限制您的查询:

代码语言:javascript
复制
SELECT * FROM workers 
WHERE status = 'ok' AND worker_id NOT IN($processed_workers) LIMIT 5

现在,在PHP而不是FOR中,使用WHILE遍历作业和工作记录集。

另一件有趣的事情是每个作业需要多长时间才能执行。看起来您的解决方案不是异步的,所以可能是作业本身造成了瓶颈,而不是查询。

票数 0
EN

Stack Overflow用户

发布于 2014-09-11 00:08:47

我认为0MQ解释的Divide and Conquer策略可能会对您有所帮助:

术语

首先,在你的问题中,“工作”这个词有两种含义:

  1. 有“工作”,意思是最终产生最终结果的工作总量。我会一直叫它作业,

  1. ,还有一个需要运行的进程的迭代。所以这是一个工人会做一件事的一次。我把这叫做任务。

因此,一个作业由X个任务组成。

策略

  • 有一个可以启动作业的呼吸机。这意味着将初始任务添加到“命令队列”中。
  • 具有任意数量的工作人员来完成实际工作。单个worker将从“命令队列”中提取单个任务,对其进行处理,并将结果推送到“结果队列”。
  • 有一个接收器,它将从“结果队列”中收集结果。它可以做以下两件事中的一件:

代码语言:javascript
复制
1. The _job_ is not yet done (needs more iterations), so it will push a new _task_ to the "command queue".
2. The _job_ is done, so it will store the final result somewhere.

为此,任务的有效负载需要包括作业需要运行的次数以及作业已经运行的次数。

不同类型的工作

这里有两种可能的方法:

  1. 具有多种类型的工作器。您还需要多个“命令队列”,每种类型的worker都需要从专用于该类型的队列中提取任务。接收器还需要知道(基于任务的有效负载)它需要将新任务添加到哪个“命令队列”中。
  2. 有一种知道如何执行所有不同任务的工作者类型。将需要完成的工作类型包括在任务的有效负载中。这样工人就知道该怎么做了。

这些方法中哪一种更可行取决于实际工作是什么。所以你必须选择你自己。

优势

此设置的主要优点是:

  • 您可以根据需要添加任意数量的工作进程,这些工作进程将并行运行。你甚至可以把它们放在不同的服务器上。
  • 你不需要一个中央数据存储(像SQL数据库)来运行一个完整的作业。您仍然可以使用数据库作为源来启动作业和/或存储最终结果,但两者之间的所有内容都将作为有效负载传递。

工具

您可以选择喜欢的任何类型的消息队列或任务管理器。你可以在Queues.io上找到一个很好的列表。

我建议你也看看React (事件驱动的,非阻塞I/O的PHP),它可以帮助你实现异步。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25672089

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档