多个Unicorn实例(Rails)中的竞争条件

时间:2017-07-01 01:17:39

标签: ruby-on-rails nginx concurrency

假设我有一个控制器操作,需要花费大量时间来执行,并且在两者之间执行多个数据库操作,并且只有在整个操作都是原子操作时它们才能正常工作。

如果我有几个应用程序的实例分布在多个服务器中,使用Nginx余额加载器,换句话说,如果两个请求同时命中,它们将开始由两个不同的服务器同时处理。

在这种情况下,避免种族状况问题的方法是什么?它看起来像任何分布式应用程序都会受到影响。

2 个答案:

答案 0 :(得分:1)

  

假设我有一个控制器动作,需要花费大量时间来执行,并且在两者之间执行多个数据库操作,并且它们只有在整个动作是原子的时候才能正常工作

如果竞争条件是由数据库操作引起的,那么一个解决方案是将这些操作包装在transaction中,这将确保ACID属性。

在Rails中,您可以通过Active Record Transaction执行以下操作:

ActiveRecord::Base.transaction do
  database operation 1
  database operation 2
  ...
end

请注意,每个数据库连接都会执行Active Record Transaction。如果要包装多个ActiveRecord类,而这些类又存储在多个数据库中,则一种解决方法是嵌套事务

Class1.transaction do 
  Class2.transaction do
     database operation 1
     database operation 2
  end
end

但这似乎不是一个优雅的解决方案。更多关于here

答案 1 :(得分:1)

添加到Son Nguyens的回答中,我想提一提,除了数据库事务之外,在执行长时间运行的进程时锁定特定记录或集合通常也很有帮助。

ActiveRecord同时支持pessimisticoptimistic锁定,但根据我的经验,在这种情况下,悲观锁定通常会更加强大。

进一步说明,根据实际操作需要多长时间,使用Sidekiq或类似功能将处理移动到后台通常是个好主意。除了具有较差的用户体验之外,长时间运行的请求通常需要在Web服务器上进行特殊配置。 Heroku甚至会在30秒后停止处理请求。