我在表中有很多条目用于执行作业。这可以扩展到几台服务器。
当服务器获取一堆行以添加到其自己的作业队列时,它们应该被“锁定”,以便其他服务器不会获取它们。 执行更新时,时间戳会增加并且“解锁”。
我目前通过在表中更新一个名为“jobserver”的字段来执行此操作,该字段默认为null,并带有jobserver的id。
作业服务器仅选择字段为空的行。
处理完所有行时,会更新其时间戳,最后将作业字段再次设置为null。
所以我需要同步这个:
$jobs = mysql_query("
SELECT itemId
FROM items
WHERE
jobserver IS NULL
AND
DATE_ADD(updated_at, INTERVAL 1 DAY) < NOW()
LIMIT 100
");
mysql_query("UPDATE items SET jobserver = 'current_job_server' WHERE itemId IN (".join(',',mysql_fetch_assoc($jobs)).")");
// do the update process in foreach loop
// update updated_at for each item and set jobserver to null
每个服务器在无限循环中执行上述操作。如果没有返回任何字段,则所有内容都为2日期(最后更新时间不超过24小时)并发送至10分钟。
我目前有MyIsam,我想继续使用它因为它在我的情况下比innodb有更好的性能,但我听说innodb有ACID交易。
所以我可以执行select和update as one。但这看起来和工作怎么样?
问题是我无法承受锁定表或其他东西,因为其他进程需要读/写且无法锁定。
我也对更高级别的解决方案(如共享信号量等)持开放态度。问题是需要跨多个服务器进行同步。
一般是理智吗?你会采用不同的方式吗?
如何同步作业selectino以确保两台服务器不更新相同的行?
答案 0 :(得分:2)
您可以先运行UPDATE但使用SELECT上的WHERE和LIMIT。然后,选择将jobserver字段设置为服务器的行。
答案 1 :(得分:1)
如果您无法负担锁定表格,那么我会根据未修改的行进行更新。类似的东西:
$timestamp = mysql_query("SELECT DATE_SUB(NOW(), INTERVAL 1 DAY)");
$jobs = mysql_query("
SELECT itemId
FROM items
WHERE
jobserver IS NULL
AND
updated_at < ".$timestamp."
LIMIT 100
");
// Update only those which haven't been updated in the meantime
mysql_query("UPDATE items SET jobserver = 'current_job_server' WHERE itemId IN (".join(',',mysql_fetch_assoc($jobs)).") AND updated_at < ".$timestamp);
// Now get a list of jobs which were updated
$actual_jobs_to_do = mysql_query("
SELECT itemId
FROM items
WHERE jobserver = 'current_job_server'
");
// Continue processing, with the actual list of jobs
您甚至可以组合选择和更新查询,如下所示:
mysql_query("
UPDATE items
SET jobserver = 'current_job_server'
WHERE jobserver IS NULL
AND updated_at < ".$timestamp."
LIMIT 100
");