Ruby on rails 使用Sidekiq的缓冲区和批处理作业

Ruby on rails 使用Sidekiq的缓冲区和批处理作业,ruby-on-rails,ruby,sidekiq,Ruby On Rails,Ruby,Sidekiq,我有一个运行非常频繁的sidekiq作业,每个作业都使用Rails中的ActiveRecord更新一个MySQL数据库记录: HTTP request -> RecordUpdateWorker(id, value) -> Record.find(id).update(value: value) 这会导致数据库死锁超时。似乎没有重复的作业,但是ID彼此靠近,所以我只能猜测这是由于。无论如何,我的解决方案是“缓冲”作业,并减少批量执行作业的频率。不需要立即执行它们,因此对于这

我有一个运行非常频繁的sidekiq作业,每个作业都使用Rails中的ActiveRecord更新一个MySQL数据库记录:

HTTP request
  -> RecordUpdateWorker(id, value)
  -> Record.find(id).update(value: value)
这会导致数据库死锁超时。似乎没有重复的作业,但是ID彼此靠近,所以我只能猜测这是由于。无论如何,我的解决方案是“缓冲”作业,并减少批量执行作业的频率。不需要立即执行它们,因此对于这个用例,它不会引起问题

HTTP Request
  -> Add Record to Buffer
  -> Occasionally run RecordUpdateWorker()
  -> Record.where(id: ids_from_buffer).update_all(value: values_from_buffer)
  # I'd have lots of flexibility to tune the transaction size, etc here 
有没有办法通过sidekiq或sidekiq附加组件来实现这一点?我已经在其他地方使用了批处理(Sidekiq Pro),但它似乎不适合这个用例。一个显而易见的解决方案是只使用一个定制的Redis队列和一个重复的作业(或者类似于执行sidekiq唯一作业时的
until_和_),但如果有一个标准方法来实现这一点,我宁愿使用它

我已经看过sidekiq文档,包括pro和enterprise,没有找到任何与此描述完全匹配的文档


编辑:将死锁更改为锁定超时,因为我不确定这是否是死锁情况。

sidekiq是否会重试,最终一切都会完成?@Daiku是的,在某些情况下,重试可以解决问题,但在重试3次(此作业的最大重试次数)后,我经常会得到失败的作业。这可能是因为重试仍然受到群体行为的影响。这也是一个问题,因为死锁会对数据库造成很大的压力,所以我宁愿完全避免这种情况。对于
.find(id)
您没有
id
索引?如果是这样,根据我的理解,这不应该导致间隙锁,而是行锁。你在系统中有没有其他竞争性的查询可能导致该记录被锁定?@Matthew是的,我想我对间隙锁定不是很了解,根据文档,它不应该在我的索引主键上起作用。有一个外键引用另一个表,这似乎会导致间隙锁,但不幸的是,我的知识到此为止。如果你看到我犯了一个明显的错误,我希望你能指出这一点,但除此之外,我的问题的方向更多地是关于缓冲和批处理sidekiq作业。不过,谢谢你,你已经指出我可能需要更好地理解MySQL锁定。对于所讨论的记录,它有什么关联,以及主id和父id有索引吗?此外,我认为这与MySQL知识无关,我只是想知道是否是其他查询导致您要更新的行(已编制索引)被锁定。sidekiq是否会重试,最终一切都会完成?@Daiku是的,在某些情况下,重试可以解决问题,但在重试3次(此作业的最大重试次数)后,我经常会得到失败的作业。这可能是因为重试仍然受到群体行为的影响。这也是一个问题,因为死锁会对数据库造成很大的压力,所以我宁愿完全避免这种情况。对于
.find(id)
您没有
id
索引?如果是这样,根据我的理解,这不应该导致间隙锁,而是行锁。你在系统中有没有其他竞争性的查询可能导致该记录被锁定?@Matthew是的,我想我对间隙锁定不是很了解,根据文档,它不应该在我的索引主键上起作用。有一个外键引用另一个表,这似乎会导致间隙锁,但不幸的是,我的知识到此为止。如果你看到我犯了一个明显的错误,我希望你能指出这一点,但除此之外,我的问题的方向更多地是关于缓冲和批处理sidekiq作业。不过,谢谢你,你已经指出我可能需要更好地理解MySQL锁定。对于所讨论的记录,它有什么关联,以及主id和父id有索引吗?此外,我认为这与MySQL知识无关,我只是想知道是否是其他查询导致您要更新的行(已编制索引)被锁定。