Недавно столкнулся с интересной проблемой, когда попытка отдать большой файл через Sinatra::Helpers.send_file приводила к отжиранию всей оперативной памяти (типичный размер файла — 14Gb).

Исследование показало, что Sinatra сама читает и отдает файл кусками по 512 байт, но web-сервер thin (а также WEBrick) буферизует вывод в оперативной памяти на своем уровне, что и приводит к таким печальным последствиям.

Для решения проблемы достаточно оказалось перейти на web-сервер Rainbows (web-сервер, базирующийся на коде unicorn, но предназначенный для работы без проксирования, для медленных клиентов и/или сервисов). Но при отдаче больших файлов процесс кушал порядка 30% CPU на одном ядре.

Rainbows позволяет оптимизировать отдачу файлов, используя, к примеру, гем sendfile, который предоставляет соответствующие API операционной системы. Но для этого необходимо, чтобы отдача файла шла через Rack::File API.

В текущей master-ветке Sinatra метод send_file переписали, используя API Rack::File, поэтому мы можем просто бэкпортировать соответствующий функционал в существующие версии гема Sinatra: