我有一個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