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

47

我对了解在Rails应用程序中处理大文件上传的不同方法,2-5GB文件感兴趣。

我明白为了传输这么大的文件,需要将它分成较小的部分。我已经做了一些研究,以下是我目前的进展。

  • 需要服务器端配置才能接受大型POST请求,可能需要64位机器来处理超过4GB的文件。
  • AWS支持多部分上传
  • HTML5 FileSystemAPI具有持久性上传器,可以将文件分块上传。
  • 有一个Bitorrent库,但这需要一个传输客户端,这并不理想。
我能否像FTP一样恢复所有这些方法,我不想使用FTP的原因是我希望在Web应用程序中保留它。我已经使用了Carrierwave和Paperclip,但我正在寻找一些可以恢复上传的东西,因为上传5GB文件可能需要一些时间!
在我列出的这些方法中,我想了解哪些方法效果很好,是否有其他方法我可能会错过?如果可能的话,请不要使用插件,不想使用Java Applets或Flash。另一个问题是这些解决方案在上传时将文件保存在内存中,如果可能的话,我也想避免这种限制。
6个回答

38

我曾在几个网站上遇到这个问题,使用了你上面介绍的一些技巧以及其他一些未提到的技巧。好消息是,实际上允许大规模上传文件是相当现实的。

很多取决于你上传文件后实际要做什么...你需要对文件进行更多处理,就越接近你的服务器。如果你需要对上传文件进行即时处理,你可能需要使用纯Rails解决方案。如果不需要进行任何处理,或者它不是时间关键性的,则可以开始考虑“混合”解决方案...

信不信由你,我实际上使用mod_porter非常成功。 Mod_porter使Apache完成应用程序通常执行的一系列任务。它有助于在上传期间不占用线程和大量内存。它会生成一个本地文件,便于处理。如果您注意处理上传的文件的方式(考虑流),即使对于传统上相当昂贵的操作,整个过程也可以使用非常少的内存。这种方法只需要非常少的实际设置才能使应用程序正常工作,并且无需实际修改您的代码,但它确实需要特定的环境( Apache服务器)以及配置的能力。

我也使用jQuery-File-Upload非常成功,它支持分块和可恢复上传等好的功能。如果没有像mod_porter这样的东西,即使在上传期间,它仍然可以占用整个执行线程,但如果正确执行,它应该对内存有不错的表现。这也会生成一个“接近”的文件,因此易于处理。这种方法需要调整您的视图层来实现,并且不能在所有浏览器中使用。

您提到FTP和BitTorrent作为可能的选项。这些选项并不像您想象的那样糟糕,因为您仍然可以将文件获取得非常接近服务器。它们甚至不是相互排斥的,这很好,因为(正如您指出的那样)它们需要另一个可能不存在于上传计算机上的客户端。基本上,这是通过设置一个区域将它们导出,并且该区域对您的应用程序可见来实现的。然后,如果您需要进行任何处理,您可以运行cron作业(或任何其他方法)监视上传位置以触发服务器的处理方法。这不能让您获得以上方法所能提供的即时响应,但是您可以将间隔设置得足够小以获得非常接近的时间。这种方法唯一的真正优势是所使用的协议更适合传输大型文件,但从我的经验来看,额外的客户端需求和分段过程通常会超过任何好处。
如果您根本不需要进行任何处理,则最好的选择可能是直接将它们放在S3上。除了将它们作为静态资源提供之外,这种解决方案也会失败....
我没有在Rails应用程序中使用HTML5 FileSystemAPI的经验,因此无法对此发表评论,尽管似乎它会显着限制您能够支持的客户端。
不幸的是,并没有真正的万能药 - 所有这些选项都需要在您尝试实现的环境中进行权衡。例如,您可能无法配置Web服务器或永久写入本地文件系统。值得一提的是,在大多数环境中,我认为jQuery-File-Upload可能是您最好的选择,因为它只需要对您的应用程序进行修改,因此您可以最轻松地将实现移动到另一个环境。

6

这个项目是基于HTTP的新协议,支持大文件断点续传。它通过提供自己的服务器来绕过Rails。

http://tus.io/


3

1

@eabharam..使用亚马逊时存在一些性能问题。我已经尝试过一次了。 - Catmandu

1

1

我也想列出一些选项,以帮助其他寻找真实解决方案的人。

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

显然,我们尝试了使用Sidekiq后台作业进行本地处理,但在大型上传(如1GB及以上)期间,它会变得不可承受。

我们尝试了tuts.io,但我个人认为它不像Jquery文件上传那样容易设置。

因此,我们尝试使用AWS...按照下面列出的步骤进行移动,它就像一个魅力一样工作....直接从浏览器上传到S3

  • 使用React drop zone uploader,我们将多个文件上传到S3。
  • 我们为输入桶设置了Aws Lambda,以触发该桶上所有类型的对象创建。
  • 此Lambda转换文件,然后再次将重新处理过的文件上传到另一个输出桶,并使用Aws SNS通知我们跟踪哪些成功哪些失败。
  • 在Rails侧......我们只是动态使用新的输出桶,然后使用Aws Cloud-front分布式系统提供服务。
你可以查看Aws关于MediaConvert的笔记,以获取一步一步的指南,他们还有一个写得很好的Github仓库,用于各种实验。
因此,从用户的角度来看,他可以上传一个大文件,在S3上启用Acceleration,React库显示上传进度,一旦上传完成,Rails回调API会再次验证其在S3 BUCKET中的存在,如mybucket/user_id/file_uploaded_slug,然后通过简单的提示消息向用户确认。
如果需要,您还可以配置Lambda在成功上传/编码时通知最终用户。
请参阅此文档-https://github.com/mike1011/aws-media-services-vod-automation/tree/master/MediaConvert-WorkflowWatchFolderAndNotification 希望能对这里的某些人有所帮助。

嗨@Milind,你的实现是否也能报告多个上传文件的进度?如果是,你是如何处理的? - markmoxx
1
请提供更多细节,@markmoxx - Milind
太好了,谢谢 @Milind - markmoxx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接