Rails / Dragonfly / Apache - Rack :: Cache - как использовать X-Sendfile? - PullRequest
2 голосов
/ 02 ноября 2011

Я использую Dragonfly для обслуживания обработанных изображений для моего приложения Rails.Dragonfly использует Rack :: Cache для будущих посещений этих обработанных изображений, так что Dragonfly не придется обрабатывать эти изображения снова и снова, тратя таким образом процессорное время.

Моя проблема начинается здесь: если я прав, что отправка файла через 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 ?

Информация о моей настройке:

  • Rails 3.1.1
  • Пассажир 3.0.9
  • CentOS
  • Установлен модуль Sendfile, насколько я знаю.В моей конфигурации виртуального хоста указаны XSendFile On и XSendFilePath /path/to/app, и Apache не жалуется, что директива XSendFile не существует.

Спасибо!

ОБНОВЛЕНИЕ 6 ноября 2011 г.

На основании этого старого обновления , если Rack::Sendfile находится перед Rack::Cache, будет использоваться X-Sendfile.Я так и сделал, и вот как мое промежуточное ПО выглядит как .Однако файлы по-прежнему не имеют тега X-Sendfile .Опять же, я не знаю, является ли это верным способом определения, включен ли X-Sendfile, поэтому я проверил очередь пассажиров.Кажется, что очередь сильно обременена, когда я захожу на страницу.

ОБНОВЛЕНИЕ 7 ноября 2011

Кажется, это чисто Rack :: Cache and Rails 3.1вопрос.В то время как Rack :: Cache поддерживает использование X-Sendfile через Rack :: Sendfile (как я уже упоминал выше, Rack :: Cache, при использовании Disk EntityStore, т.к.возвращаемое тело является подклассом 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. В чем причина того, что собственные решения Rack :: Cache не использовались для Rails 3.1?Почему у Rails есть свои?
  2. Есть ли причина, по которой Маршал используется?Есть ли причина, по которой вместо этого следует отправлять поток данных?

Я оказался глубже, чем обычно, и буду удивлен, если я правильно все понял.Я надеюсь найти ответ!

Ответы [ 2 ]

1 голос
/ 16 сентября 2012

В итоге я заставил это работать, хотя и с nginx & unicorn, а не с Apache & Passenger.

Как вы указали в вашей проблеме Github , вы можете переключить Rack :: Cacheвернемся к использованию стандартного файла: / 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 делает это в разработке, и вы все равно можете это сделатьв производстве, если хотите.Предостережение при этом заключается в том, что если вы используете какую-либо из функций кэширования Rails, использующих Rack :: Cache, записи кэша будут храниться в этом хранилище, а не в стандартном Rails, поэтому вам придется учитывать это, если вам нужноочистите любую из этих записей вручную.

Затем вам также необходимо убедиться, что вы вставили промежуточное программное обеспечение Rack :: Sendfile в начало стека с аргументом config.action_dispatch.x_sendfile_header.Без аргумента config Rack :: Sendfile не будет добавлять заголовок.

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

My Gist показывает мои соответствующие строки в production.rb и мой шаблон nginx.Должно быть легко адаптировано для работы с модулем Apache X-Sendfile.

Еще одна вещь, которую стоит отметить при тестировании, это то, что если вы отправляете запрос HEAD только через cURL, например, вы не получитесоответствующий заголовок X-Sendfile в ответе, так как Rack :: Cache фактически не отправляет тело для запроса HEAD, и поэтому Rack :: Sendfile не имеет ничего для вызова to_path.

1 голос
/ 19 декабря 2011

В качестве альтернативы Varnish вы можете использовать Apache mod_disk_cache.Настроить было бы меньше, поскольку вы уже используете Apache.

...