Как загружать большие файлы на Heroku (особенно видео)

Я использую heroku для размещения веб-приложения, основное внимание в котором уделяется размещению видео. Видео размещаются через vimeo pro, и я использую vimeo gem от matthooks, чтобы справиться с процесс загрузки. Загрузка работает для небольших файлов, но не для больших (например, ~50 МБ).

Просмотр журналов heroku показывает, что я получаю ошибку http 413, что означает «Слишком большой объект запроса». Я полагаю, что это может быть связано с ограничением, которое heroku устанавливает для загрузки файлов (более 30 МБ, согласно этой веб-странице). Однако проблема заключается в том, что любая информация, которую я могу найти по этому вопросу, кажется устаревшей и противоречивой (например, эта страница, которая утверждает, что ограничений по размеру нет). Я также не мог найти ничего на сайте heroku по этому поводу.

Я поискал в Google и нашел несколько релевантных страниц (одну и два), но нет решений, которые работал на меня. Большинство страниц, которые я нашел, связаны с загрузкой больших файлов на amazon s3, что отличается от того, что я пытаюсь сделать.

Вот соответствующий вывод журналов:

2012-07-18T05:13:31+00:00 heroku[nginx]: 152.3.68.6 - - [18/Jul/2012:05:13:31 +0000]
  "POST /videos HTTP/1.1" 413 192 "http://neoteach.com/components/19" "Mozilla/5.0 
  (Macintosh; Intel Mac OS X 10.7; rv:13.0) Gecko/20100101 Firefox/13.0.1" neoteach.com

Других ошибок в журналах нет. Это единственный вывод, который появляется, когда я пытаюсь загрузить слишком большое видео. Это означает, что это не ошибка тайм-аута или проблема с превышением выделенной памяти на дино.

Действительно ли heroku ограничивает размер загрузки? Если да, то есть ли способ изменить этот лимит? Обратите внимание, что сами файлы вообще не хранятся на серверах heroku, они просто передаются на серверы vimeo.

Если проблема не в ограничении размера загрузки, кто-нибудь знает, что еще может пойти не так?

Большое спасибо!


person stephenalexbrowne    schedule 18.07.2012    source источник
comment
Насколько я знаю, такого пути нет. Пришлось загружать напрямую на S3. Возможно, вы сможете найти какой-нибудь способ передать видео напрямую в Vimeo, но единственный результат, который я нашел для этого, был не очень обнадеживающим: vimeo.com/forums/topic:28113   -  person Qsario    schedule 18.07.2012
comment
Стоит отметить, что я только что протестировал загрузку файла размером 8,5 МБ в приложение Heroku, что заняло 3 минуты 15 секунд (да, у меня есть DSL). У меня web: gunicorn -t 60 -k "eventlet" -w 3 myapp.wsgi:application в моем Procfile. Другими словами, я увеличил время ожидания до 60 секунд, и мое приложение позволяет загружать файлы более 3 минут. Я не уверен в причине этого, но это как-то связано с тем, что мой Dyno разрешает одновременные соединения.   -  person orokusaki    schedule 04.11.2013


Ответы (3)


Обновление:

ОП здесь. Я до сих пор не совсем понимаю, почему я получаю именно эту ошибку 413, но мне удалось найти решение, которое работает с помощью s3_swf_upload гем. Реализация включает флэш-память, что далеко не идеально, но это было единственное решение (из 3 или 4, которые я пробовал), которое я смог заставить работать.

Как указал Нил (спасибо, Нил!), я должен был получить сообщение об ошибке «H12 — тайм-аут запроса». И я столкнулся с этой ошибкой после повторных испытаний. Проблема возникает, когда вы пытаетесь загрузить большие файлы на сервер heroku с вашего контроллера (используя веб-дино), потому что серверу требуется слишком много времени, чтобы ответить на почтовый запрос.

Правильный подход — отправить файл напрямую на s3, минуя героку.

Вот общий обзор моего подхода:

  1. Используйте гем s3_swf_upload, чтобы предоставить форму прямой загрузки на s3.
  2. Определите, когда файл будет загружен, с помощью функции обратного вызова javascript, предоставленной в драгоценном камне.
  3. Используя javascript, отправьте рельсам почтовое сообщение, чтобы ваш сервер знал, что загрузка файла завершена.
  4. Контроллер, который отвечает на публикацию javascript, делает две вещи: (a) присваивает атрибут s3_key видеообъекту (подается как параметр в форме). (b) запускает фоновую задачу с помощью гема delayed_job.
  5. Фоновая задача извлекает файл из s3. Для этого я использовал гем aws-sdk, так как он уже был включен в s3_swf_upload. Обратите внимание, что это заметно отличается от драгоценного камня aws-s3 (фактически они конфликтуют друг с другом).
  6. После того, как файл был получен из s3, я использовал гем vimeo, чтобы загрузить его на vimeo (все еще в задний план).

Приведенная выше реализация работает, но не идеальна. Для файлов размером около 500 МБ вы все равно столкнетесь с ошибками R14 в рабочих динамометрах. Это происходит из-за того, что heroku выделяет только 512 МБ памяти на dyno, поэтому вы не можете загрузить весь файл в память сразу. Обойти эту проблему можно путем реализации своего рода фрагментации на последнем шаге, когда вы извлекаете файл из s3 и загружаете его в vimeo по частям. Я все еще работаю над этой частью, и я хотел бы услышать любые ваши предложения.

Надеюсь, это может помочь кому-то. Не стесняйтесь задавать мне любые вопросы. Как я уже сказал, мое решение не идеально, поэтому не стесняйтесь добавлять свой собственный ответ, если считаете, что он может быть лучше.

person stephenalexbrowne    schedule 26.07.2012
comment
Посмотрите на Carrierwave с помощью Fog и CarrierwaveDirect - person Narfanator; 12.02.2013

Я думаю, что лучшим вариантом здесь действительно является загрузка непосредственно на S3. Это намного дешевле и намного безопаснее, чем позволять пользователям загружать файлы на ваш собственный сервер (или в данном случае на Heroku). Это также хорошо зарекомендовавший себя шаблон, используемый многими платформами видеохостинга (я знаю, что vzaar делает это).

Ознакомьтесь с подключаемым модулем загрузки jQuery, который позволяет напрямую загружать файлы в S3: https://github.com/blueimp/jQuery-File-Upload

Также проверьте Railscasts по этой теме: #381 и #383.

person grokling    schedule 30.10.2012

Ваша самая большая проблема заключается не в размере файлов, а в том, что вы ожидаете, что пользователь загрузит большие файлы в Heroku, а затем передаст их дальше. Проблема здесь в том, что все запросы на платформе Heroku должны возвращать первый байт в течение 30 секунд, что в вашем случае очень маловероятно.

Поэтому вам нужно подумать о том, чтобы заставить пользователей загружать файлы напрямую на S3/Vimeo/куда угодно, а затем подключать данные вашего приложения к этим загруженным ресурсам.

Если вы используете Ruby, возможно, стоит взглянуть на драгоценный камень прямой передачи несущей, чтобы узнать, как это делается. В противном случае есть сторонние службы, которые позволяют вам сделать это с помощью некоторого кода, который вы можете добавить на страницу, но за них взимается дополнительная плата.

person Neil Middleton    schedule 18.07.2012
comment
Спасибо, Нейл, описанная выше проблема не связана с тайм-аутом. В логах нет H12 - Request timeout. Однако я понимаю, что тайм-аут представляет собой большой риск при загрузке больших файлов, поэтому я рассмотрю прямую загрузку. Возможно, это также решит проблему, описанную выше. - person stephenalexbrowne; 18.07.2012
comment
Должно. Я предполагаю, что вы тестировали приличное соединение до сих пор. - person Neil Middleton; 18.07.2012
comment
Тайм-аут истекает только тогда, когда соединение простаивает в течение 30 секунд. - person James Ward; 18.07.2012
comment
@James — 30 секунд до первого байта: https://devcenter.heroku.com/articles/http-routing#timeouts - person Neil Middleton; 20.07.2012
comment
Спасибо, Нил, за разъяснения. Также похоже, что тайм-аут составляет 55 секунд между байтами после первого. - person James Ward; 20.07.2012