10

嘿。我使用delayed_job進行後臺處理。我有8個CPU服務器,MySQL和我開始7 delayed_job的處理Rails運行多個delayed_job - 鎖表

RAILS_ENV=production script/delayed_job -n 7 start 

Q1: 我想知道是有可能,2個或更多的delayed_job進程開始處理同樣的處理(相同的記錄行中數據庫delayed_jobs)。我檢查了delayed_job插件的代碼,但無法以應該的方式找到鎖定指令(無鎖定表或SELECT ... FOR UPDATE)。

我認爲每個進程都應該在執行lock_by列上的UPDATE之前鎖定數據庫表。他們通過更新locked_by字段來鎖定記錄(UPDATE delayed_jobs SET locked_by ...)。這真的夠了嗎?不需要鎖定?爲什麼?我知道UPDATE的優先級高於SELECT,但我認爲這在這種情況下不起作用。

我的MULTY線程情況的理解是:

Process1: Get waiting job X. [OK] 
Process2: Get waiting jobs X. [OK] 
Process1: Update locked_by field. [OK] 
Process2: Update locked_by field. [OK] 
Process1: Get waiting job X. [Already processed] 
Process2: Get waiting jobs X. [Already processed] 

我認爲在某些情況下,更多的就業機會可以得到相同的信息,並可以開始處理相同的過程。

Q2: 是7 delayed_jobs對8CPU服務器來說是一個好數字嗎?爲什麼是/不是。

Thx 10x!

回答

11

我想回答你的問題是在「LIB/delayed_job的/ job.rb」 168行:

self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?)", id, (now - max_run_time.to_i)]) 

這裏行的更新時,才執行,如果沒有其他工人已經鎖定作業,並檢查表是否已更新。由於您的DBMS確保將單個查詢的執行與其他查詢的影響隔離開來,因此不需要表鎖或類似(這會大大降低應用程序的性能)。在您的示例中,Process2無法獲取作業X的鎖定,因爲它更新了作業表格,當且僅當它未鎖定之前。

第二個問題:這取決於。在8臺CPU服務器上。這是專門爲這項工作,8名工人是一個很好的起點,因爲工人是單線程,你應該爲每個核心運行一個。根據您的設置,或多或少,工人們會更好。這很大程度上取決於你的工作。充分利用多核心的優勢?或者你的工作等待大部分時間用於外部資源?您可以嘗試不同的設置並查看所有涉及的資源。

+0

所以你說每個過程都是原子風格的過程,並且是安全的? – xpepermint 2010-04-25 14:24:51

+0

我認爲這裏缺少的是SELECT ... FOR UPDATE。 ? – xpepermint 2010-04-25 15:25:55

+0

查詢是原子的。因此,如果執行查詢UPDATE作業SET locked_at ='..',locked_by = 1 WHERE id = 12和(locked_at爲null或locked_at <'..')',那麼locked_at和locked_by只會在沒有其他有效的鎖。 DBMS首先檢查where條件然後執行更新,並確保行之間沒有更改。因此你不能覆蓋一個存在的鎖。 – gregor 2010-04-25 17:20:59