Ruby on Rails环回请求导致死锁?

时间:2013-01-15 20:30:07

标签: ruby-on-rails thin unicorn

解决方案

我正在开发模式中切换到独角兽。需要一个针对每个递归级别的工作进程来防止死锁情况,因此我运行了2个工作进程。

问题

我正在开发环境中的Thin服务器上工作。我使用端口3000(dev环境中的默认值)。我的问题是让服务器向自己发出请求。

假设我有以下控制器:

# app/controllers/recursions_controller.rb
class RecursionsController < ApplicationController

    # /recursions
    def index

        # synchronously call recursions#show
        RestClient.get("http://localhost:3000/recursions/1") 

        # finish!
        render :text => 'index'

    end

    # /recursions/:id
    def show

        # finish immediately
        render :text => 'show'

    end

end

以下是相应的路线:

# config/routes.rb
resources :recursions

这是我最初请求recursions#index时请求日志的输出:

[INFO] 2013-01-15 12:09:05 -0800 Started GET "/recursions" for 127.0.0.1 at 2013-01-15 12:09:05 -0800
Processing by RecursionsController#index as HTML
Completed 500 Internal Server Error in 60049ms

[FATAL] 2013-01-15 12:10:05 -0800 RestClient::RequestTimeout (Request Timeout):
  app/controllers/recursions_controller.rb:8:in `index'
  Rendered /usr/local/lib/ruby/gems/1.9.1/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_trace.erb (0.8ms)
  Rendered /usr/local/lib/ruby/gems/1.9.1/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.7ms)
  Rendered /usr/local/lib/ruby/gems/1.9.1/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (7.4ms)

[INFO] 2013-01-15 12:10:05 -0800 

[INFO] 2013-01-15 12:10:05 -0800 

[INFO] 2013-01-15 12:10:05 -0800 Started GET "/recursions/1" for 127.0.0.1 at 2013-01-15 12:10:05 -0800
Processing by RecursionsController#show as XML
  Parameters: {"id"=>"1"}
  Rendered text template (0.0ms)
Completed 200 OK in 7ms (Views: 5.5ms)

我怀疑这里发生的事情是某种僵局。请求A在请求B返回之前无法返回(递归排序,无法帮助),但是在请求A返回之前无法处理请求B(我的网络服务器内置了明显的限制?)。当RestClient超时时会解决死锁,导致异常并终止带有500的请求A.只有这样才能处理请求B,尽管此时此处没有实际意义。

在我看来,我的网络服务器无法处理并发请求。那就是说,这是我的问题:

  1. 我可以在我的开发环境中切换到一个不受限制的网络服务器吗?我们在生产中使用Unicorn,它可以产生多个工作进程,因此处理并发请求,但Unicorn对于开发环境来说似乎太重了。使Unicorn成为我的问题的解决方案的同样的事情可能使得难以读取日志输出。这是我最后的解决方案。

  2. 是否有一种棘手的方式向Rails / Rack框架发出请求以避免明显的并发请求限制?

  3. 任何人都可以向我提供明确说明这种情况的文档吗?我不知道它是否是所有单进程Ruby on Rails webservers固有的限制,或者只是Thin。

  4. 注意:这只是一个玩具问题,可以证明我遇到的阻止问题。如果您需要知道实际原因,那就是我将一些HTTP服务从我们基础架构的另一部分移动到我们的RoR应用程序中。我们的RoR应用程序在我们的代码中的许多不同点消耗这些服务,因此我试图保持这些服务的客户端代码不变,只改变实现。这意味着发出循环HTTP请求。这将在以后日期进行优化,届时一切都会稳定下来。

2 个答案:

答案 0 :(得分:5)

您是正确的,默认情况下,您的应用一次只会处理一个请求。此限制由Rack::Lock中间件实现 - 无论您使用何种网络服务器,它都会存在。

您可以通过在相应的environment.rb文件中调用config.thread_safe!来更改此设置。但是,rails的开发模式代码重新加载不是线程安全的,并且被此设置禁用,这使得它在开发中不能真正使用。究竟是什么config.thread_safe!在rails configuration guide

中描述了 乘客,战俘,独角兽都可以轻松运行多个实例。

答案 1 :(得分:1)

我和我的一个客户遇到了这个问题。正如您所描述的那样 - 由于您运行的是仅包含一个进程的单线程Web服务器,因此您一次只能使用一个客户端。如果您发出第二个请求或环回请求,则第二个请求将由操作系统排队,直到第一次出现。

切换到独角兽本身并没有解决问题,但在我们的情况下,我们使用的是独角兽,我们只是将工人数量提高到了'2'。我不熟悉,不足以推荐如何增加工人数量,但毫无疑问有办法。否则,使用独角兽 - 如果你进行了切换,你也会得到更好的dev / prod奇偶校验,所以它可能是值得的。