在 Rails 应用程序中处理大文件上传的最佳方法是啥?

Posted

技术标签:

【中文标题】在 Rails 应用程序中处理大文件上传的最佳方法是啥?【英文标题】:What is the best approach to handle large file uploads in a rails app?在 Rails 应用程序中处理大文件上传的最佳方法是什么? 【发布时间】:2013-05-20 21:58:48 【问题描述】:

我有兴趣了解在 Rails 应用程序中处理大文件上传(2-5Gb 文件)的不同方法。

我了解,为了传输这种大小的文件,需要将其分解为更小的部分,我已经进行了一些研究,这就是我目前所掌握的。

需要服务器端配置来接受大型 POST 请求,并且可能需要 64 位机器来处理 anything over 4Gb。 AWS 支持multipart upload. html5 FileSystemAPI 有一个持久上传器,可以分块上传文件。 Bitorrent 的库,尽管这需要一个不理想的传输客户端

是否可以像 FTP 一样恢复所有这些方法,我不想使用 FTP 的原因是如果可能的话,我想保留在 Web 应用程序中?我使用了carrierwave和回形针,但我正在寻找能够恢复的东西,因为上传5Gb文件可能需要一些时间!

在我列出的这些方法中,我想了解哪些方法效果很好,是否还有其他方法我可能会遗漏?如果可能没有插件,宁愿不使用 Java Applets 或 Flash。另一个问题是这些解决方案在上传时将文件保存在内存中,这也是我希望尽可能避免的约束。

【问题讨论】:

【参考方案1】:

我已经在几个网站上处理了这个问题,使用了一些您在上面说明的技术和一些您没有使用的技术。好消息是,允许大量上传实际上是非常现实的。

这在很大程度上取决于您在上传文件后实际计划对文件执行的操作...您必须对文件执行的工作越多,您就越希望它与您的服务器越近。如果您需要立即处理上传,您可能想要做一个纯 rails 解决方案。如果不需要做任何处理,或者时间要求不高,可以开始考虑“混合”解决方案……

信不信由你,我实际上在使用mod_porter 时运气不错。 Mod_porter 使 apache 完成了您的应用程序通常会完成的大量工作。它有助于在上传期间不占用线程和一堆内存。它会在您的应用程序中生成一个本地文件,以便于处理。如果您注意处理上传文件的方式(想想流),您可以使整个过程使用非常少的内存,即使对于传统上相当昂贵的操作也是如此。这种方法几乎不需要对您的应用进行实际设置即可运行,也不需要对您的代码进行真正的修改,但它确实需要特定的环境(apache 服务器)以及配置它的能力。

我还很幸运地使用了jQuery-File-Upload,它支持分块上传和可恢复上传等好东西。如果没有 mod_porter 之类的东西,这仍然会在上传期间占用整个执行线程,但如果处理得当,它应该在内存上不错。这也导致文件“关闭”,因此易于处理。这种方法需要调整您的视图层才能实现,并且不适用于所有浏览器。

您提到了 FTP 和 bittorrent 作为可能的选项。这些选项并不像您想象的那么糟糕,因为您仍然可以让文件非常接近服务器。它们甚至不是互斥的,这很好,因为(正如您所指出的)它们确实需要一个额外的客户端,该客户端可能存在也可能不存在于上传机器上。基本上,它的工作方式是设置一个区域让他们转储到您的应用程序可以看到的区域。然后,如果您需要进行任何处理,您可以运行一个 cron 作业(或其他)来监视该位置的上传并触发您的服务器处理方法。这不会让您立即获得上述方法可以提供的响应,但您可以将间隔设置得足够小以非常接近。这种方法唯一真正的优势是所使用的协议更适合传输大文件,根据我的经验,额外的客户端要求和分散的进程通常超过任何好处。

如果您根本不需要任何处理,最好的选择可能是直接与他们一起进入 S3。该解决方案在您实际上需要对文件执行任何操作而不是将它们作为静态资产服务的那一刻就失败了......

我没有在 Rails 应用程序中使用 HTML5 FileSystemAPI 的任何经验,所以我无法谈论这一点,尽管它似乎会显着限制您能够支持的客户端。

遗憾的是,没有一颗真正的灵丹妙药 - 所有这些选项都需要根据您要完成的任务与您的环境进行权衡。例如,您可能无法配置 Web 服务器或永久写入本地文件系统。对于它的价值,我认为 jQuery-File-Upload 可能是您在大多数环境中的最佳选择,因为它只需要修改您的应用程序,因此您可以最轻松地将实现移动到另一个环境。

【讨论】:

【参考方案2】:

这个项目是一个基于 HTTP 的新协议,支持大文件的可恢复上传。它通过提供自己的服务器绕过 Rails。

http://tus.io/

【讨论】:

【参考方案3】:

http://www.jedi.be/blog/2009/04/10/rails-and-large-large-file-uploads-looking-at-the-alternatives/ 对选项进行了一些很好的比较,包括 Rails 之外的一些选项。

请仔细阅读。这对我的情况很有帮助

另外一个站点是:- http://bclennox.com/extremely-large-file-uploads-with-nginx-passenger-rails-and-jquery

如果其中任何一个不起作用,请告诉我

【讨论】:

【参考方案4】:

我会绕过 Rails 服务器并将您的大文件(拆分为块)直接从浏览器发布到 Amazon Simple Storage。看看这个post 使用 javascript 分割文件。我有点好奇这个设置的性能如何,我想在这个周末修改这个设置。

【讨论】:

@eabharam.. 使用 amazon 时有一点性能问题。试过一次【参考方案5】:

我认为 Brad Werth 找到了答案

只有一种方法可以直接上传到 S3(即使您在理论上可以使用 aws lambda 通知您的应用程序之后确实需要一些重新处理......但老实说,我只是在这里猜测,我大约为了自己解决同样的问题,我稍后会对此进行扩展)

http://aws.amazon.com/articles/1434

如果你使用载波

https://github.com/dwilkie/carrierwave_direct_example Uploading large files on Heroku with Carrierwave

【讨论】:

【参考方案6】:

让我也确定一些可能有助于其他人寻找现实世界解决方案的选项。

我有一个带有 Ruby 2.7 的 Rails 6,这个应用程序的主要目的是创建一个类似于 Google 驱动器的环境,用户可以在其中上传图像和视频,然后他们再次处理它们以获得高质量。

显然,我们确实尝试过使用 Sidekiq 后台作业进行本地处理,但在 1GB 及以上的大型上传过程中它会变得不堪重负。 我们确实尝试过 tuts.io,但我个人认为设置起来并不像 Jquery 文件上传那样容易。

因此,我们按照下面列出的步骤对 AWS.. 进行了实验,它的效果非常棒....从浏览器直接上传到 S3

使用 React 拖放区上传器...我们将多个文件上传到 S3。 我们为输入存储桶设置 Aws Lambda,以便在该存储桶上创建所有类型的对象时触发。 此 Lambda 转换文件并再次将重新处理的文件上传到另一个文件 - 输出存储桶,并使用 Aws SNS 通知我们以跟踪哪些工作有效,哪些失败。 在 Rails 方面...我们只是动态使用新的输出存储桶,然后通过 Aws Cloud-front 分发提供它。

您可以查看 MediaConvert 上的 Aws 说明以查看分步指南,他们还有一个编写良好的 Github 存储库,可用于各种实验。

所以,从用户的角度来看,他可以上传一个大文件,在 S3 上启用Acceleration,React 库显示上传进度,一旦上传,Rails callback api 再次验证它在 S3 中的存在像 mybucket/user_id/file_uploaded_slug 这样的 BUCKET,然后通过简单的 Flash 消息向用户确认。 如果需要,您还可以配置 Lambda 以通知最终用户上传/编码成功。

请参阅此文档 - https://github.com/mike1011/aws-media-services-vod-automation/tree/master/MediaConvert-WorkflowWatchFolderAndNotification

希望对这里的人有所帮助。

【讨论】:

嗨@Milind,您的实施是否还报告多次上传的文件进度?如果是这样,您是如何处理的? 添加细节@markmoxx 太好了,谢谢@Milind

以上是关于在 Rails 应用程序中处理大文件上传的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 Rails 中播种数据库的最佳方法是啥?

在 Rails 中处理视图和仅帮助程序常量的最佳方法

在rails和carrierwave中上传之前显示图像预览的最佳方式

在 Rails 应用程序中上传和裁剪图像的最佳方式是啥?

在 Rails 中验证多封电子邮件和处理错误的最佳方法是啥?

在graphql中处理文件上传的最佳方法是啥?