Rails/Dragonfly/Apache - Rack::Cache - как использовать X-Sendfile?

Я использую 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?

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

  • Рельсы 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 и Rails 3.1. В то время как Rack::Cache поддерживает использование X-Sendfile через Rack::Sendfile (как я уже упоминал выше, Rack::Cache, при использовании Disk EntityStore, так как responseds_to to_path поскольку возвращаемое тело является подклассом 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#.

Мои вопросы

Чтобы помочь мне решить, следует ли мне исправлять это или заставить Rails вместо этого использовать собственный дисковый магазин Rack::Cache, у меня есть несколько вопросов:

  1. В чем причина того, что собственные решения Rack::Cache для хранения данных не использовались для Rails 3.1? Почему у Rails есть свои?
  2. Есть ли причина использования маршала? Есть ли причина, по которой поток данных должен отправляться обратно?

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

2 ответа

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

Я закончил тем, что заставил это работать, хотя с 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 на.

Другие вопросы по тегам