我有几个工作,需要完成X次,我有不同的工人与他们自己的信息。
除此之外,作业有一个日期,我想在作业到达下一个作业之前处理它Y次,从最早的作业开始。
一个工人只能处理一个作业一次。
目前,我正在使用mysql数据库和php脚本来实现这一点,但是似乎在每秒50个作业的速度上存在瓶颈,我需要更快的速度,所以我必须寻找替代方案。
我的设置有以下表格:
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 ):
$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"
}
}
}我希望这能解释我所需要的。我甚至不知道这到底是怎么叫的。
我读过关于queues,task schedulers和messaging systems的文章,但这里的问题是,我需要由不同的工作者多次执行一个作业,这些工作者按last_processed排序。
我认为我前面提到的这些构造的工作原理就像你把一些作业放进去,然后它们就会一个接一个地被执行。使用我的设置,我想我需要从一开始就分配工人,然后例如将作业1/ 1000次分配给不同的工人。
这对我来说是个问题。有时工作进程并不总是可用的,如果我现在将工作进程1和作业2放在一起,如果它在几分钟内被执行,那么工作进程1就不会有响应。这就是为什么我现在在执行时分配一个工作的工人给一个作业。
task scheduler需要更易于管理,我需要能够暂停和恢复单个作业,并根据工作人员的“表行”中的不同标准选择它们。
我希望有活跃的300+工作者在队列系统上工作,而不会出现问题。一个worker在大约1秒内执行一个作业,因此这将是每秒完成的300+作业。
理想情况下,我希望有一个像Amazon AWS这样的云设置,其中我有一个实例作为任务调度器,还有几个其他实例来执行作业。
要达到这样的效果,最好的设置是什么?我现在拥有的mysql解决方案似乎是最方便、最合适的。也许有一个更快的数据库用于该作业,具有类似的功能?
发布于 2014-09-21 15:19:19
尽管我们的老师告诉我们,有这样一个愚蠢的问题;这就是为什么你到目前为止没有得到一个像样的答案。
这一次,我将花时间解释为什么这个问题是愚蠢的,希望未来的读者以及您自己都能从中受益,而不是忽略您提出的问题。
我希望300+工作人员在队列系统上积极工作,不会出现问题
这说明了一种误解;它表明您认为您的硬件能够并发执行300个线程,但这不是:我敢打赌,在我们有生之年不会有这样的硬件可供我们使用。
Multi-Threading in PHP with pthreads
有一种浪费的倾向;这是一个常见的误解,认为线程化任何东西都可以让它更快,但事实并非如此。更多的线程并不总是等同于更多的吞吐量,同样地,更多的水并不总是等同于更湿。

跳出框框思考是一个好的多线程程序员的先决条件;常识应该表明,更多的水确实意味着更湿,但如果你考虑一下碗底部的中心点:一旦它是湿的,无论你在上面放多少水,它都不会变得更湿……
水太多,线太多,你会被淹没的。
你应该阅读所有引用的文档,它应该让你很好地理解什么是可能的,以及如何实现的。
发布于 2014-09-09 23:33:23
关于您的查询,我注意到的一件事是,您选择了FOR循环中的所有记录。
不使用GROUP BY,而是使用ORDER by,因为我相信这就是您正在尝试做的事情,并限制查询本身中的作业数量:
SELECT * FROM jobs
WHERE times_executed < to_be_done
ORDER BY last_processed ASC LIMIT 10由于作业只能由单个工作人员完成,因此您应该考虑使用LIMIT
SELECT * FROM workers
WHERE status = 'ok' AND worker_id NOT IN($processed_workers) LIMIT 1如果您计划将相同的工作分配给5个可用员工,则仍会限制您的查询:
SELECT * FROM workers
WHERE status = 'ok' AND worker_id NOT IN($processed_workers) LIMIT 5现在,在PHP而不是FOR中,使用WHILE遍历作业和工作记录集。
另一件有趣的事情是每个作业需要多长时间才能执行。看起来您的解决方案不是异步的,所以可能是作业本身造成了瓶颈,而不是查询。
发布于 2014-09-11 00:08:47
我认为0MQ解释的Divide and Conquer策略可能会对您有所帮助:
术语
首先,在你的问题中,“工作”这个词有两种含义:
,
因此,一个作业由X个任务组成。
策略
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.
为此,任务的有效负载需要包括作业需要运行的次数以及作业已经运行的次数。
不同类型的工作
这里有两种可能的方法:
这些方法中哪一种更可行取决于实际工作是什么。所以你必须选择你自己。
优势
此设置的主要优点是:
工具
您可以选择喜欢的任何类型的消息队列或任务管理器。你可以在Queues.io上找到一个很好的列表。
我建议你也看看React (事件驱动的,非阻塞I/O的PHP),它可以帮助你实现异步。
https://stackoverflow.com/questions/25672089
复制相似问题