假设我有一个控制器操作,需要花费大量时间来执行,并且在两者之间执行多个数据库操作,并且只有在整个操作都是原子操作时它们才能正常工作。
如果我有几个应用程序的实例分布在多个服务器中,使用Nginx余额加载器,换句话说,如果两个请求同时命中,它们将开始由两个不同的服务器同时处理。
在这种情况下,避免种族状况问题的方法是什么?它看起来像任何分布式应用程序都会受到影响。
答案 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同时支持pessimistic和optimistic锁定,但根据我的经验,在这种情况下,悲观锁定通常会更加强大。
进一步说明,根据实际操作需要多长时间,使用Sidekiq或类似功能将处理移动到后台通常是个好主意。除了具有较差的用户体验之外,长时间运行的请求通常需要在Web服务器上进行特殊配置。 Heroku甚至会在30秒后停止处理请求。