2

我正在使用Dragonfly为我的 Rails 应用程序提供处理后的图像。Dragonfly 依赖Rack::Cache来访问那些处理过的图像,这样Dragonfly 就不必一次又一次地处理这些图像,从而浪费 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),因为它会产生一个响应#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

我知道,根据网络上的帖子,我应该看到如下内容:

X-Sendfile: /path/to/file

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

关于我的设置的信息:

  • 导轨 3.1.1
  • 乘客 3.0.9
  • 中央操作系统
  • 据我所知,已安装 Sendfile 模块。我已经在我的虚拟主机配置XSendFile OnXSendFilePath /path/to/app指定了,并且 Apache 没有抱怨该指令XSendFile不存在。

谢谢!

更新 2011 年 11 月 6 日

基于这个旧的更新,只要Rack::Sendfile放在前面Rack::Cache,就会使用X-Sendfile。我做到了,这就是我的中间件的样子。但是,这些文件仍然没有 X-Sendfile 标签。同样,我不知道这是否是确定 X-Sendfile 是否启用的可靠方法,所以我检查了乘客队列。当我访问一个页面时,队列似乎受到了很大的阻碍。

2011 年 11 月 7 日更新

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

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

我的问题

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

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

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

4

2 回答 2

1

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

正如您在Github 问题中指出的那样,您可以将 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

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

如果您正在对此进行测试,需要注意的另一件事是,例如,如果您仅通过 cURL 发送 HEAD 请求,您将不会在响应中获得相关的 X-Sendfile 标头,因为 Rack::Cache 不会实际发送正文一个 HEAD 请求,所以 Rack::Sendfile 没有什么可调用to_path的。

于 2012-09-16T05:43:12.080 回答
1

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

于 2011-12-19T15:33:11.673 回答