Высокое потребление памяти загрузка больших файлов на Sinatra и Thin

#ruby #sinatra #rack #thin #eventmachine

#ruby #sinatra #стойка #тонкий #eventmachine

Вопрос:

Я запускаю приложение Sinatra на Thin.

Вот упрощенный вид кода:

 class StreamApp < Sinatra::Base
  get "/" do
    s3_object = # large S3 object (not loaded into memory)
    stream do |out|
      s3_object.read do |chunk|
        out << chunk
      end
    end
  end
end
  

По мере продолжения потоковой передачи объем памяти на коробке начинает увеличиваться до такой степени, что он достигает максимума, и процесс просто умирает.

Я читал статьи 2009 года, в которых говорилось, что это была проблема с EventMachine и буферизацией данных в стойке до тех пор, пока весь ответ не будет завершен.

Кто-нибудь видел эту проблему или нашел обходной путь для этого?

Ответ №1:

Способ, которым потоковая передача в sinatra работает в eventmachine, заключается в том, что для каждого вызова out << chunk sinatra запланирован вызов в eventmachine для отправки фрагмента. Проблема с вашим кодом заключается в том, что он блокирует цикл обработки событий eventmachines до тех пор, пока не будет прочитан весь файл и чтение не будет выполнено. Таким образом, ничего не будет отправлено, пока все данные не окажутся в памяти.

это можно обойти, выполнив что-то вроде:

 get "/" do
s3_object = # large S3 object (not loaded into memory)
  stream :keep_open do |out|
    reader = lambda {
       chunk = s3_object.read
       break if chunk == nil
       out << chunk
       EM::next_tick amp;reader
    }
    reader.call
  end
end
  

это прочитает один фрагмент, как только eventmachine будет готов, не блокируя цикл событий. Конечно, в этом случае s3_object.read нужно возвращать только один фрагмент за раз.

Комментарии:

1. Хм, это имеет смысл. Я попытаюсь воссоздать это, поскольку это была проблема давным-давно, и мы перешли от поддержки этого кода. Тем не менее, я все же хотел бы посмотреть, устраняет ли это проблему.