1

我有一个具有以下环境的生产网站:

  • 导轨 2.3.5
  • MySQL 服务器 5.1.33
  • Enterprise Ruby 1.8.6(2008-08-11 补丁级别 287)[x86_64-linux]
  • mysql 宝石 2.7
  • 旧版本的 BackgrounDRb 插件在 4 个不同的服务器上运行用于后台任务,每个有 5 个不同的工作人员(Ruby 线程,而不是单独的进程!)。

BackgrounDRb 工作人员之一使用“乐观锁定”的变体处理作业队列:

    update_sql = "update jobs
                  set updated_at = CURRENT_TIMESTAMP,
                      in_process = 1
                  where id = #{job.id} and in_process = 0"

    affected_rows = Job.connection.update(update_sql)
    captured_job = affected_rows > 0 ? Job.find(job.id) : nil

上面的代码尝试使用给定的 ID 和 in_process 字段的额外条件来更新记录。因此,如果同一记录已由不同的服务器/进程更新,则 UPDATE 语句将仅返回 0(零),并且该作业不会由 2 个不同的服务器同时处理。

问题是:有时“Job.connection.update(update_sql)”即使实际更新了记录也会返回 0(零)!只有在代码中添加了大量日志记录后,我才能发现这一点。它只发生在晚上我们负载很重的生产中......

我的猜测是 mysql gem 使用了一些全局变量(类变量)来影响 BackgrounDRb 进程的所有 5 个线程,但我不确定。我正在查看 mysql gem 和 ActiveRecord 的代码,但我不明白它是如何工作的。

这怎么可能发生?

2010-07-07 更新:我们决定不使用线程进行作业处理——这将解决我们所有的问题:每个作业处理器都是一个单独的进程 :)

4

0 回答 0