【发布时间】: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 On和XSendFilePath /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 自己的磁盘存储,我有一些问题:
- Rails 3.1 没有使用 Rack::Cache 自己的存储解决方案的原因是什么?为什么 Rails 有自己的?
- 是否有使用 Marshal 的原因?是否有理由改为发回数据字节流?
我比平时更深入,如果我理解正确,我会感到惊讶。希望能找到答案!
【问题讨论】:
-
我四处询问,向 Rails 用户组发送电子邮件,但没有找到答案。是的,一开始 Varnish 听起来有点矫枉过正,但为了让 X-Sendfile 正常工作,我需要进行所有更改,安装 Varnish 会更简单。
标签: ruby-on-rails apache x-sendfile rack-cache