2011-11-02 49 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

相關問題