【发布时间】:2015-02-12 01:56:45
【问题描述】:
我有一个 PHP 脚本,它从数据库中检索行,然后根据内容执行工作。这项工作可能很耗时(但计算量不一定很昂贵),因此我需要允许多个脚本并行运行。
数据库中的行如下所示:
+---------------------+---------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------+------+-----+---------------------+----------------+
| id | bigint(11) | NO | PRI | NULL | auto_increment |
.....
| date_update_started | datetime | NO | | 0000-00-00 00:00:00 | |
| date_last_updated | datetime | NO | | 0000-00-00 00:00:00 | |
+---------------------+---------------+------+-----+---------------------+----------------+
我的脚本当前选择date_last_updated 中日期最早的行(工作完成后更新)并且不使用date_update_started。
如果我现在要并行运行脚本的多个实例,它们会选择相同的行(至少在某些时候)并且会完成重复的工作。
我想做的是使用事务来选择行,更新date_update_started 列,然后在选择行的SQL 语句中添加WHERE 条件以仅选择date_update_started 更大的行比某个值(以确保另一个脚本无法处理它)。例如
$sth = $dbh->prepare('
START TRANSACTION;
SELECT * FROM table WHERE date_update_started > 1 DAY ORDER BY date_last_updated LIMIT 1000;
UPDATE table DAY SET date_update_started = UTC_TIMESTAMP() WHERE id IN (SELECT id FROM table WHERE date_update_started > 1 DAY ORDER BY date_last_updated LIMIT 1000;);
COMMIT;
');
$sth->execute(); // in real code some values will be bound
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
根据我的阅读,这本质上是一个队列实现,在 MySQL 中似乎不被接受。尽管如此,我需要找到一种方法来允许多个脚本并行运行,经过研究,这就是我想出的。
这种方法行得通吗?有没有更好的办法?
【问题讨论】:
-
如何运行并行脚本?
-
@Lupin 目前该脚本通过 cron 作业每 15 分钟执行一次。该脚本检查另一个实例是否正在运行,如果是,则终止。我不确定我将如何管理多个正在运行的脚本——我可能在数据库中有一个计数器来查看有多少正在运行并以这种方式限制实例的数量,但一次一个问题:-)跨度>
-
好的,还有一些问题需要我完全理解: 1. 您有一个脚本可以选择行并对其进行处理,然后将其更新回数据库,对吗? 2. 您希望能够在不同的行上运行并行脚本并执行相同的操作,对吗? 3. 每次脚本运行时,选择的行是连续的,意思是它们是 1-100、101-200 等还是它们在 id 方面是随机的并且仅由那些 date_update_started 大于 1 的行选择?
-
@Lupin 1. 是,2. 是,3. 根据日期字段和示例中未显示的另一个字段选择行。因此它们不是严格“连续”的,而是按两个字段排序的。
-
另一种方法是让某种主脚本获取一些行(例如
SELECT ... LIMIT 5),然后为这些行中的每一行启动一个处理脚本的单独实例。您甚至可以使用第二个表来跟踪当前正在运行的处理实例的数量,因此每当 cron 启动您的主脚本时,它就会知道要获取多少行。但由于这甚至与您的要求不相近,因此我决定将其添加为评论而不是答案。