2011-11-02 46 views
5

我们在AWS中托管我们的网站。我们目前在一个集群中有3个EC2实例,使用AWS负载平衡器。如何将CRON任务设置为每组实例只运行一次?

服务器有linux,apache,java,mysql和tomcat 6.0。

我们正在决定如何设置每小时运行的任务。 Java代码中显而易见的地方是这样的,但有一个问题。

问题是,由于我们在集群中有3个实例(都是相同的),因此任务将在一小时内运行3次,而不是每小时运行一次,每个实例运行一次。

我有几个想法来克服这个问题,但希望有一个更好的,可能是一个行业标准,如何管理这个。

一个想法是存储在数据库中,它已经运行。任务将会看到它已经运行了或不运行。尽管如此,我仍然看到了错误。

另一个想法是使用cron安装在本地操作系统中的一个实例上,而不是Tomcat中的代码。这将使用wget来调用一个调用java方法的网页。因为那只会调用其中一个实例,所以它只能运行一次。

这两种方式看起来像黑客和容易出错。有没有一种真正的方法来做到这一点?

回答

3

我已经使用了cron/wget解决方案,它实际上是解决问题的合理方法。您的系统管理员会欣赏能够控制它。

另一种解决方案是使用JVM系统属性来指示哪个实例是运行作业的实例。例如:-DschedulerEnabled=true。只在其中一个实例上设置该标志,并且只有在该标志被设置时才会运行作业调度代码。

最后,Quartz支持您的基于DB的解决方案,它的Clustering功能。这样做的好处是它是一个真正的高可用性解决方案。如果作为作业调度程序的计算机出现故障,则其他解决方案必须手动故障切换到另一台计算机。

+0

此外,刚刚发现rcron也可以解决它:https://code.google.com/p/rcron/ – razzed

3

虽然有一个公认的答案,但有一些简单的本土解决方案没有上面列出的错误。 wget解决方案可以很好地确保单个服务器运行代码,但会增加安全性问题(您应该使用共享的专用访问密钥来保护URL),并且@sourcedelica还指出了哪个服务器应该实际调用的问题cron任务。

我倾向于去哪些工作,无论你的系统数量的解决方案 - 而且也不需要为不同的系统不同的cron配置。

的假设是,在路上你可能会增加新的机器,你的主服务器(一个配置来运行你的cron任务,例如)可能死亡或终止。

我已经开发了一个解决方案使用其可以用两个简单的表来实现集群数据库锁:

CREATE TABLE `Server` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `uname` varchar(32) NOT NULL, 
    `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `alive` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`) 
); 

CREATE TABLE `Lock` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    `code` varchar(128) NOT NULL, 
    `pid` int(10) unsigned DEFAULT NULL, 
    `server` int(10) unsigned DEFAULT NULL, 
    `locked` timestamp NULL DEFAULT NULL, 
    `used` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `code` (`code`) 
); 

每个系统具有独特的uname,如果不存在登记的记录;每次更新alive

获得锁:一旦你用的32。如果serverpid都是NULL id有你Lock

SELECT * FROM Lock WHERE code='cron-cluster'; 

如果它不存在,

INSERT INTO `Lock` ... 

,设置它们到我的服务器id和当前进程ID,使用数据库的原子性质来确保只有一个。

UPDATE Lock SET server=1,pid=4233 WHERE id=32 AND server IS NULL and pid IS NULL; 

然后,你再一个选择,看看你是否真正获得它(假设n个不同的机器正试图获得在同一时间锁):

SELECT COUNT(id) FROM Lock WHERE code='cron-cluster' AND server=1 AND pid=4233; 

如果结果是1 ,你已经获得锁定,0意味着另一个过程。

最后需要的是让每个服务器清理死锁和死亡服务器;每个服务器负责检查每个锁定的Lock正在运行的活动进程,并且在某个超时之后,Server未更新为alive时,删除与该服务器及其Server记录关联的所有锁定。

我添加其他的服务器性能的Server表允许的磁盘空间,CPU等的监测

虽然没有强大的石英集群,它可以解决你的问题。

+0

爱你的工作,这一个给了我我缺乏的洞察力的洞察力。我使用MySQL的cron可以在任何频繁的时间间隔运行,我用了4小时: ''UPDATE锁定SET服务器= 1,lock_date = NOW()WHERE lock_date shazbot

相关问题