适用于图片密集型应用的最佳Ruby on Rails架构

14

我正在开发一个允许大量照片上传的应用程序,想了解处理这个问题的最佳设置。

目前我使用的工具如下:

  • Jquery文件上传:允许用户拖放图像
  • CarrierWave:使用ImageMagick处理和调整图像大小
  • Amazon S3:CarrierWave通过Fog将图像上传到Amazon S3
  • Heroku:用于托管

我希望能够允许用户在页面上拖放大量的图像,然后在后台进行上传时导航到其他页面。我也希望随着上传完成,图片可以逐渐显示出来。我不想使这个过程锁定Heroku动态进程,所以我可能需要将工作移至后台任务中,但我不确定针对我的情况应该使用什么工具。

这种类型的应用程序最佳设置是什么?我应该使用哪个后台处理工具?Cloudinary是一个好主意吗?


添加上传模块到 Web 服务器以避免在文件复制时产生不必要的 CPU 利用率。 - Viren
2个回答

34

我最近构建了一个应用程序,可以在Heroku上接受大量上传。我决定自己构建解决方案,而不是使用cloudinary或类似的解决方案。以下是我学到的一些经验教训:

  • 不要将文件上传到Heroku。整个网络工作线程将在上传期间完全锁定。这可能需要长达一分钟的时间。是不可接受的。

  • 使用JavaScript上传工具(如jquery-file-upload)直接上传到s3。这起初有点复杂,但一旦你搞定了,它就非常好用了。您可以使用s3_direct_upload gem,或者您可以阅读其源代码,从头开始创建自己的解决方案。该gem基于一个付费的railscasts pro视频,但其源代码可用

  • 当上传完成后,通过ajax请求向您的应用程序传递新的s3 url作为远程url。然后,Carrierwave将像上传一样在s3上处理该图像,只需几秒钟而不是长达一分钟。

  • 使用jquery-file-upload的客户端图像调整大小。有人会尝试上传5MB的照片,然后抱怨上传速度太慢。这将使所有上传尽可能快。

  • 配置s3以自动清除您的上传文件夹

  • 不要使用 thin,改用 unicorn。thin 处理请求时间太长,但使用 3 到 4 个 unicorn worker 更加宽容。

  • 不要使用 rmagick。虽然它有更好的 API 来进行复杂图像处理,但会消耗大量内存,建议使用 mini_magick。

  • 您会注意到,我没有为任何这些内容使用后台工人。如果您真的非常细心,可以将接收远程 url 的控制器传递其工作给后台工作者,并且如果立即需要结果,则后台工作者可以通过 pubsub(例如 faye 或 pusher,可能使用令人兴奋的新 sync gem)通知 UI。但对于我的应用程序来说并不必要,我宁愿将钱花在另一个 web dyno 上而不是 worker dyno 上。

    如果你想让他们在此期间点击整个应用程序,那么你需要上传一个弹出窗口(并使用某种 pubsub 解决方案),或者使用 ember、backbone 或 angular 等构建整个站点作为 JavaScript 应用程序。

    还有问题吗?


    在Web Dyno上进行任何处理,即使只有几秒钟,都会出现响应问题。 Heroku的负载平衡层不再知道每个Dyno是否实际可用于处理请求。 请求随机平衡到所有Dynos,并且来自其他用户的请求可能会在您的图像处理请求作业后等待3-5秒,即使另一个Dyno可以立即处理该请求。 在Heroku上始终保持请求超级快速是最好的选择。来源文章 - Brian McKelvey
    1
    同意。这就是为什么Heroku将官方推荐从thin改为unicorn,问题要少得多的原因所在。最佳架构涉及到工作进程,但并不是所有应用程序都需要,当然也不会像直接使用S3上传那样产生相同的影响。 - Taavo

    6
    在你提到之前,我从未见过Cloudinary,但它似乎非常适合你的项目。
    首先,它可能会极大地简化你的应用程序。Cloudinary通过其HTTP API支持直接从浏览器上传,并且已经有一个基于jQuery文件上传的jquery插件,具有类似的功能,包括客户端预上传处理。
    此外,它支持类似于dragonfly(也是一个非常好的库)的即时转换。
    这意味着,除非你真的需要通过你的应用程序上传这些图片,否则你可以完全规避它,直接上传到Cloudify,并通过他们的转换API处理图像裁剪和其他转换。
    如果需要的话,您可以从应用程序中删除Carrierwave和S3,当然也不需要任何后台dynos来处理图像处理。此外,这样做可能会更快(直接上传和即时操作,而不是上传到应用程序,处理,然后上传到云端),并且可以消除通过您的应用程序上传的带宽。
    即使没有直接上传,似乎Cloudinary提供了一个Carrierwave插件,仍然可以利用其转换API,从而避免了应用程序处理图像的需要。

    这会允许用户发布一组照片,然后在后台上传(所以他们可以离开页面而不停止上传过程)吗? - Jonathan Sutherland
    我认为如果不打开弹出窗口来处理上传,这是不可能实现的。否则,当你离开页面时,它会中断上传。据我所知,在Web浏览器中没有进程后台运行的功能。 - numbers1311407
    然而,根据您的需求,您仍然可能会向堆栈添加某种推送组件,例如Faye或某些WebSocket实现,这将使您能够推送有关上传图像的通知。 - numbers1311407

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