【问题标题】:Rails/Dragonfly/Apache - Rack::Cache - how to use X-Sendfile?Rails/Dragonfly/Apache - Rack::Cache - 如何使用 X-Sendfile?
【发布时间】:2011-11-02 12:14:13
【问题描述】:

我正在使用 Dragonfly 为我的 Rails 应用程序提供处理后的图像。 Dragonfly 依赖 Rack::Cache 来访问那些处理过的图像,因此 Dragonfly won't have to process those images again 和再次访问,从而浪费 CPU 时间。

我的问题从这里开始:如果我是正确的,通过 Rack::Cache 发送文件仍然会占用 Rails 进程,那么查看包含 30 个图像的页面,即使这些图像的文件大小很小,也会占用Rails 处理得非常快。如果更多的访问者来查看该页面,那么他们将体验到非常缓慢的响应时间。如何通过 X-Sendfile 获取这些文件?

我在production.rb 中设置了以下内容,但我知道这些是针对来自 Rails 的资产,而不是 Dragonfly 文件:

config.serve_static_assets = false
config.action_dispatch.x_sendfile_header = "X-Sendfile"

我知道 Rack::Cache 以某种方式支持 X-Sendfile(可能通过Rack::Sendfile),因为它是produces a body that responds to #to_path。但是,我不知道如何启用它。当我检查来自 Rack::Cache 的文件时,我没有看到任何 X-Sendfile 信息:

Date: Wed, 02 Nov 2011 11:38:28 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.9
Content-Disposition: filename="2.JPG"
Cache-Control: public, max-age=31536000
Etag: "3174d486e4df2e78a5ff9174cacbede5787d4660"
X-Content-Digest: c174408eda6e689998a40db0aef4cdd2aedb3b6c
Age: 28315
X-Rack-Cache: fresh
Content-Length: 22377
Status: 200
Content-Type: image/jpeg

我知道,基于posts around the net,我应该看到类似的内容:

X-Sendfile: /path/to/file

最后我不知道我必须配置它的 Dragonfly 还是 Rack::Cache(或两者)。 如何让 Dragonfly 和/或 Rack::Cache 通过 X-Sendfile 提供文件

关于我的设置的信息:

  • Rails 3.1.1
  • 乘客 3.0.9
  • CentOS
  • 据我所知,Sendfile 模块已安装。我在我的虚拟主机配置中指定了 XSendFile OnXSendFilePath /path/to/app,Apache 没有抱怨指令 XSendFile 不存在。

谢谢!

2011 年 11 月 6 日更新

基于this old update,只要将Rack::Sendfile放在Rack::Cache前面,就会使用X-Sendfile。我做到了,这就是my middleware looks like。但是,这些文件是still don't have the X-Sendfile tag。同样,我不知道这是否是确定是否启用 X-Sendfile 的可靠方法,所以我检查了乘客队列。当我访问一个页面时,队列似乎受到了很大的阻碍。

2011 年 11 月 7 日更新

看来这纯粹是 Rack::Cache 和 Rails 3.1 的问题。虽然 Rack::Cache 支持通过 Rack::Sendfile 使用 X-Sendfile(就像我上面提到的,Rack::Cache,当使用 Disk EntityStore 时,因为 to_path,因为 body it returns is a subclass of File),Rails 3.1使用自己的存储解决方案。 Rails 3.1 使用ActiveSupport::Cache::FileStore,这是默认设置的,如果你没有在production.rb 文件中指定任何内容。

FileStore 的问题在于它返回的正文是要向上游发送的响应的一部分,因为该正文不响应 to_path。正文是ActiveSupport::Cache::Entry 的一个实例。您可以看到here,当要求 FileStore 读取缓存文件时,它通过返回 Entry 实例的 File.open('/path/to/file') {|f| Marshal.load(f) } 读取它。最终被上游传递并返回给客户端的值是Entry#value

我的问题

为了帮助我决定是否应该修补这个问题,或者让 Rails 使用 Rack::Cache 自己的磁盘存储,我有一些问题:

  1. Rails 3.1 没有使用 Rack::Cache 自己的存储解决方案的原因是什么?为什么 Rails 有自己的?
  2. 是否有使用 Marshal 的原因?是否有理由改为发回数据字节流?

我比平时更深入,如果我理解正确,我会感到惊讶。希望能找到答案!

【问题讨论】:

  • 我四处询问,向 Rails 用户组发送电子邮件,但没有找到答案。是的,一开始 Varnish 听起来有点矫枉过正,但为了让 X-Sendfile 正常工作,我需要进行所有更改,安装 Varnish 会更简单。

标签: ruby-on-rails apache x-sendfile rack-cache


【解决方案1】:

作为 Varnish 的替代品,您可以使用 Apache 的 mod_disk_cache。由于您已经在运行 Apache,因此设置工作量会减少。

【讨论】:

    【解决方案2】:

    我最终得到了这个工作,尽管使用的是 nginx 和 unicorn 而不是 Apache 和Passenger。

    正如您在 your Github issue 中指出的那样,您可以将 Rack::Cache 切换回使用它的标准 file:/store 而不是 rails:/store,这将允许响应响应 to_path

    config.action_dispatch.rack_cache = {
      :verbose     => true,
      :metastore   => URI.encode("file:/PATH/TO/CACHE/STORE"),
      :entitystore => URI.encode("file:/PATH/TO/CACHE/STORE")
    }
    

    Dragonfly 在开发中执行此操作,如果您愿意,您仍然可以在生产中执行此操作。这样做的警告是,如果您使用任何使用 Rack::Cache 的 Rails 缓存功能,缓存条目将存储在该存储中,而不是标准的 Rails 存储中,因此如果需要,您需要考虑这一点手动清除任何这些条目。

    然后,您还需要确保使用 config.action_dispatch.x_sendfile_header 参数将 Rack::Sendfile 中间件插入堆栈的前面。如果没有 config 参数,Rack::Sendfile 不会添加标题。

    config.middleware.insert 0, Rack::Sendfile, config.action_dispatch.x_sendfile_header
    

    My Gist 显示了我在 production.rb 和我的 nginx 模板中的相关行。应该很容易适应 Apache X-Sendfile 模块。

    如果您正在测试这一点,需要注意的另一件事是,如果您仅通过 cURL 发送 HEAD 请求,您将不会在响应中获得相关的 X-Sendfile 标头,因为 Rack::Cache 不会实际发送HEAD 请求的主体,因此 Rack::Sendfile 无需调用 to_path

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-15
      • 2012-01-17
      • 2012-04-27
      • 2011-01-06
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      相关资源
      最近更新 更多