如何在 Heroku 上上传大文件(尤其是视频)
Posted
技术标签:
【中文标题】如何在 Heroku 上上传大文件(尤其是视频)【英文标题】:How to Upload Large Files on Heroku (Particularly Videos) 【发布时间】:2012-07-17 02:32:47 【问题描述】:我正在使用 heroku 托管一个主要关注托管视频的网络应用程序。这些视频是通过 vimeo pro 托管的,我使用vimeo gem by matthooks 来帮助处理上传过程。 上传适用于小文件,但不适用于较大的文件(例如,~50mb)。
查看 heroku 日志显示我收到 http 错误 413,它代表“请求实体太大”。我相信这可能与 heroku 对文件上传的限制(大于 30mb,according to this webpage)有关。但问题是,我能找到的关于该主题的任何信息似乎都已过时且相互矛盾(例如 claims there is no size limit 的此页面)。我在 heroku 的网站上也找不到任何关于此的内容。
我搜索了谷歌并找到了一些相关的页面(one 和two),但没有适合我的解决方案。我发现的大多数页面都涉及将大文件上传到 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 的服务器上。
如果问题不在于上传大小限制,有没有人知道还有什么问题?
非常感谢!
【问题讨论】:
据我所知,没有这样的方法。我必须直接上传到 S3。您也许可以找到某种方法将视频直接传递给 Vimeo,但我发现的唯一结果并不是很令人鼓舞:vimeo.com/forums/topic:28113 值得注意的是,我刚刚测试了将一个 8.5MB 的文件上传到我的 Heroku 应用程序,这需要 3 分 15 秒(是的,我有 DSL)。我的Procfile
中有web: gunicorn -t 60 -k "eventlet" -w 3 myapp.wsgi:application
。换句话说,我已将超时时间增加到 60 秒,而我的应用程序将允许上传时间超过 3 分钟。我不确定这是什么原因,但这与我的 Dyno 允许并发连接有关。
【参考方案1】:
更新:
在这里。我仍然不确定为什么会出现这个特定的 413 错误,但我能够想出一个使用 s3_swf_upload gem 的解决方案。实施涉及闪存,这不太理想,但它是我可以开始工作的唯一解决方案(我尝试过的 3 或 4 个)。
正如 Neil 指出的(感谢 Neil!),我应该得到的错误是“H12 - 请求超时”。经过反复试验,我确实遇到了这个错误。当您尝试从控制器(使用网络测功机)将大文件上传到 heroku 服务器时会出现问题,因为服务器响应发布请求需要很长时间。
正确的做法是不经过heroku,直接将文件发送到s3。
以下是我的方法的高级概述:
-
使用 s3_swf_upload gem 向 s3 提供直接上传表单。
使用 gem 中提供的 javascript 回调函数检测文件何时完成上传。
使用 javascript,向 rails 发送一条 post 消息,让您的服务器知道文件已完成上传。
响应 javascript 帖子的控制器做了两件事:(a) 将 s3_key 属性分配给视频对象(作为表单中的参数提供)。 (b) 使用 delayed_job gem 启动后台任务。
后台任务从 s3 检索文件。我使用aws-sdk gem 来完成此操作,因为它已经包含在 s3_swf_upload 中。 请注意,这与 aws-s3 gem 明显不同(实际上它们相互冲突)。
从 s3 检索文件后,我使用 vimeo gem 将其上传到 vimeo(仍在后台)。
上面的实现是可行的,但并不完美。对于大小接近 500MB 的文件,您仍然会在工作人员测功机中遇到 R14 错误。发生这种情况是因为 heroku 只为每个测功机分配 512MB 的内存,因此您不能一次将整个文件加载到内存中。解决这个问题的方法是在最后一步中实现某种分块,从 s3 中检索文件并将其逐个上传到 vimeo。我仍在处理这部分工作,我很想听听您的任何建议。
希望这可能对某人有所帮助。有问题尽管问我。就像我说的那样,我的解决方案并不完美,所以如果您认为它可以更好,请随时添加您自己的答案。
【讨论】:
用“Fog”和“CarrierwaveDirect”看“Carrierwave”【参考方案2】:我认为这里最好的选择确实是直接上传到 S3。它比允许用户将文件上传到您自己的服务器(或本例中的 Heroku)便宜得多且安全得多。这也是许多视频托管平台使用的经过充分验证的模式(我知道 vzaar 就是这样做的)。
查看 jQuery 上传插件,它允许直接上传到 S3:https://github.com/blueimp/jQuery-File-Upload
还可以查看有关此主题的 Railscast:#381 和 #383。
【讨论】:
【参考方案3】:您最大的问题不是这里文件的大小,而是您希望用户将大文件上传到 Heroku,然后将它们传递下去。这里的问题是 Heroku 平台上的所有请求都必须在 30 秒内返回第一个字节 - 在您的情况下这不太可能。
因此,您需要考虑让用户直接上传到 S3/Vimeo/任何地方,然后将您的应用程序数据连接到这些上传的资产。
如果您使用的是 Ruby,那么载波直接 gem 可能值得一看,看看它是如何完成的。如果没有第三方服务允许您通过一些代码来执行此操作,您可以将这些代码放入页面中,但这些都需要附加费用。
【讨论】:
谢谢尼尔,我上面描述的问题似乎不是超时。日志中没有“H12 - 请求超时”。但是,我知道超时对于大文件上传来说是一个很大的风险,所以我会研究直接上传。或许这也能解决上述问题。 应该的。我猜你到目前为止一直在测试一个体面的连接。 只有当连接空闲30秒才超时。 @James - 距离第一个字节还有 30 秒:devcenter.heroku.com/articles/http-routing#timeouts 感谢尼尔澄清。看起来超时时间是第一个字节之后的字节之间的 55 秒。以上是关于如何在 Heroku 上上传大文件(尤其是视频)的主要内容,如果未能解决你的问题,请参考以下文章
在输入'php artisan storage:link'命令后,如何使用Laravel链接存储文件夹在Heroku上显示图像?