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