我有一个cron任务,每运行x秒n服务器。它将“从表中选择WHERE time_scheduled < CURRENT_TIME”,然后对此结果集执行冗长的任务。SELECT + UPDATE以避免返回相同的结果
我现在的问题是:如何避免让两台独立的服务器同时执行相同的任务?
这个想法是在选择它后以设定的时间间隔更新* time_scheduled *。但是如果两台服务器碰巧同时运行查询,那就太晚了,不是吗?
欢迎任何想法。它不一定是严格的MySQL解决方案。
谢谢!
我有一个cron任务,每运行x秒n服务器。它将“从表中选择WHERE time_scheduled < CURRENT_TIME”,然后对此结果集执行冗长的任务。SELECT + UPDATE以避免返回相同的结果
我现在的问题是:如何避免让两台独立的服务器同时执行相同的任务?
这个想法是在选择它后以设定的时间间隔更新* time_scheduled *。但是如果两台服务器碰巧同时运行查询,那就太晚了,不是吗?
欢迎任何想法。它不一定是严格的MySQL解决方案。
谢谢!
我猜你已经有一个MySQL实例,并且你的和服务器的连接可以运行这个处理任务。你正在这里实现一个工作队列。
您提到的table
需要使用InnoDB访问方法(或Percona或MariaDB提供的其他易于使用的访问方法之一)。
表中的这些项目是否需要分批处理?也就是说,它们在某种程度上是相互关联的吗?或者您的服务器进程是否可以逐个处理它们?这是一个重要的问题,因为如果您可以单独或以小批量处理它们,您将在服务器进程之间获得更好的负载平衡。我们假设小批量。
这个想法是为了防止任何服务器进程抓取您的表中的行,如果其他服务器进程有该行。我必须做很多这类事情,这里是我的建议;我知道这是有效的。
首先,为您的表添加一个整数列。称之为“工作”或某种这样的事情。给它一个默认值为零。
其次,为每台服务器分配一个永久性的id号。服务器IP地址的最后一部分(例如,如果服务器的IP地址为10.1.0.123,则ID号为123)是一个不错的选择,因为它可能在您的环境中是唯一的。
然后,当一个服务器正在抓取工作时,使用这两个SQL查询。
UPDATE table
SET working = :this_server_id
WHERE working = 0
AND time_scheduled < CURRENT_TIME
ORDER BY time_scheduled
LIMIT 1
SELECT table_id, whatever, whatever
FROM table
WHERE working = :this_server_id
第一个查询将持续获取一批要处理的行。如果另一个服务器进程同时进入,它不会占用相同的行,因为除非working = 0
,否则进程不会占用行。请注意,LIMIT 1将限制您的批量大小。你不必这样做,但你可以。我还投掷了ORDER BY
来处理等待时间最长的行。这可能是一种有用的做事方式。
第二个查询检索您需要做的工作信息。不要忘记检索正在处理的行的主键值(我称它们为table_id
)。
然后,你的服务器进程做它需要做的任何事情。
完成后,需要将行重新放回队列以备后用。要做到这一点,服务器进程需要将time_scheduled
设置为需要的任何设置,然后设置working = 0
。因此,例如,您可以针对您正在处理的每一行运行此查询。
UPDATE table
SET time_scheduled = CURRENT_TIME + INTERVAL 5 MINUTE,
working = 0
WHERE table_id = ?table_id_from_previous_query
就是这样。
除了一件事。在现实世界中,这些排队系统有时会被玷污。服务器进程崩溃。等等等见墨菲定律。你需要一个监控查询。这在这个系统中很容易。
此查询将列出逾期五分钟以上的所有作业以及应该在其上工作的服务器。
SELECT working, COUNT(*) stale_jobs
FROM table
WHERE time_scheduled < CURRENT_TIME - INTERVAL 5 MINUTE
GROUP BY WORKING
如果此查询出现空白,一切正常。如果它出现大量的working
设置为零的作业,您的服务器没有跟上。如果它出现working
设置为某个服务器的ID号的作业,该服务器正在进行午休。
如果需要,您可以重置分配给服务器的所有作业,该作业已与该查询共进午餐。
UPDATE table
SET working=0
WHERE working=?server_id_at_lunch
顺便说一句,(working, time_scheduled)
上的复合索引可能会帮助这个表现良好。
我认为这可以很好地工作。我试图实施它,看看我是否遇到了任何不可预见的问题。谢谢! – fandangosoeren
锻炼出色。再次感谢。 – fandangosoeren
mysql服务器在所有服务器之间共享? – user4035
是的,他们都从同一台服务器拉。 – fandangosoeren