【问题标题】:How can I serve requests concurrently with Rails 4?如何使用 Rails 4 同时处理请求?
【发布时间】:2014-03-03 12:58:50
【问题描述】:

我正在尝试在 Rails 4 中同时处理多个请求,而在 Rails 3 中使用 config.threadsafe!Puma 可以很容易地做到这一点。

假设我有这个控制器

class ConcurrentController < ApplicationController
  def index
    sleep 10000
  end

  def show
  end
end

我以前可以用puma -t 2:16 -p 3000(最少2个线程)启动puma,然后点击index,然后点击show,仍然可以正确渲染show

在 Rails 4 中,如果我尝试做同样的事情,Puma 现在会锁定 index 请求,而 show 永远不会被渲染。当我为服务器点击Ctrl-C 时,Puma 给了我这个错误:

Rack app error: #<ThreadError: Attempt to unlock a mutex which is locked by another thread>

为了让并发与 Rails 4 一起工作,我在这里缺少什么? config.threadsafe! 应该是不需要的(即使我尝试也不会产生影响)

【问题讨论】:

  • 你试过在生产环境中运行这个吗?
  • 应该和 Rails 4 没有区别。确实 Rails 4 默认是多线程的。您的环境/配置中一定还有其他原因导致了差异。你是如何开始彪马的?在命令行中使用该命令?您可以从 development.rb 文件中分享其他任何相关内容吗?
  • @fredrik - 请查看我的回答。我花时间解释了允许并发的选项并提供了一些参考资料。不幸的是,尽管您的回答可以得出一个切实可行的解决方案,但并不完全正确。
  • 我默认在config/environments/development.rb中使用带有config.cache_classes = false的rails 5.0.3,但没有遇到这个问题。
  • 尝试使用多个工作线程而不是多个线程,-w 2。这将启动应用程序的两个实例来处理请求。

标签: ruby-on-rails ruby concurrency puma


【解决方案1】:

你可以试试独角兽这在开发模式下很简单:

http://dave.is/unicorn.html

【讨论】:

    【解决方案2】:

    似乎默认情况下,在 Rails 4 中,开发环境中没有启用并发请求。

    我在documentation 中找到了这句话。

    Rack::Lock 将应用程序封装在互斥体中,因此一次只能由单个线程调用。仅在 config.cache_classes 为 false 时启用。

    这意味着如果config.cache_classes = false(默认情况下在开发环境中)我们不能有并发请求。

    并发请求确实适用于我在生产环境中的示例。

    一种解决方案是在开发环境中设置config.cache_classes = true,但随后代码不会在更改时重新加载,这对于开发来说实际上不起作用。

    第二种hacky解决方案是在开发中禁用Rack::Lock中间件。

    因此,如果您要在 development.rb 中添加以下行:

    config.middleware.delete Rack::Lock
    

    您应该能够在开发环境中处理并发请求禁用缓存类。

    【讨论】:

    • 您在哪里使用 MRI Ruby 或 JRuby?我的印象是多线程在这样的 MRI Ruby 示例中不起作用。
    • 我可以看到 Puma 有一个集群模式(指定工作人员):github.com/puma/puma#clustered-mode 但我无法让这个示例正常工作(使用“睡眠”)
    • 删除这个中间件@Fredrik有什么缺点?
    • @JoãoPauloMotta 请看我的回答。我证明了一个讨论您的问题的博客文章的链接。缺点是您必须处理控制器中的竞争条件。
    • Delete Rack::Lock 不适合我。它加载页面,但它让我超时连接数据库:“ActiveRecord::ConnectionNotEstablished (ActiveRecord::ConnectionNotEstablished):”
    【解决方案3】:

    我邀请您阅读本文Removing config.threadsafe!config.threadsafe!的配置选项 它将帮助您更好地理解config.threadsafe! 的选项,尤其是允许并发。

    在 Rails 4 中 config.threadsafe! 是默认设置的。


    现在回答

    在 Rails 4 中,请求在默认情况下由 DEV 环境中的 Rack::Lock 中间件包裹在 Mutex 周围。

    如果你想启用并发,你可以设置config.allow_concurrency=true。这将禁用 Rack::Lock 中间件。如您的问题的另一个答案中所述,我不会删除它;对我来说,这看起来像是一个 hack。

    注意:如果您有config.cache_classes=true,那么分配给config.allow_concurrency(Rack::Lock 请求互斥锁)将不会占用 效果,默认情况下允许并发请求。如果你有 config.cache_classes=false,那么你可以设置 config.allow_concurrencytruefalse。在开发中 你会想要这样的环境

    config.cache_classes=false
    config.allow_concurrency=true
    

    声明:表示如果config.cache_classes = false (默认情况下在开发环境中)我们不能有并发 请求。 不正确。

    附录

    您可以参考this answer,它设置了一个使用 MRI 和 JRuby 测试并发性的实验。结果令人惊讶。 MRI 比 JRuby 快。

    MRI 并发实验是on GitHub。 实验只测试并发请求。控制器中没有竞争条件。但是,我认为实现上面文章中的示例来测试控制器中的竞争条件并不难。

    【讨论】:

    • 这似乎是正确的,我会将其标记为正确答案,尽管我没有花时间测试它。不过我会注意到,config.allow_concurrency 是一个完全未记录的功能[1]。它出现在 Rails 3[2] 的文档中,但不适用于 Rails 4。
    • 是的,没错。我们没有太多关于该配置选项未来使用的文档。另外,我刚刚记得,考虑将数据库连接的连接池设置为与最大线程数相同的大小。在你的情况下 16.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 2014-04-17
    • 1970-01-01
    • 2017-03-01
    • 1970-01-01
    • 2016-12-17
    相关资源
    最近更新 更多