在 Rails 中运行大量长时间运行的后台作业

Posted

技术标签:

【中文标题】在 Rails 中运行大量长时间运行的后台作业【英文标题】:Running large amount of long running background jobs in Rails 【发布时间】:2016-10-14 21:46:34 【问题描述】:

我们正在构建一个网络应用程序,用户将在其中上传可能需要在后台处理的大文件。该任务涉及调用第 3 方 API,因此每个作业可能需要几个小时才能完成。我们使用 DelayedJob 来运行后台作业。每个用户启动一个后台作业,每一个都需要几个小时才能完成,这很快就会增加很多后台作业。我想知道为此设置部署的最佳方法是什么?我们目前托管在 DigitalOcean 上。我已经解雇了 10 名 DelayedJob 员工。每个(理想情况下)占用 157MB。主动运行时,它使用大约 900 MB。我们现在的用户群很小,所以这不是问题,但很快就会出现。所以在一个 4GB 的 droplet 上,我可能一次可以运行 2 或 3 个工人。我们应该如何处理这个问题?我们是否应该考虑使用 DigitalOcean 的 API 来按需自动旋转廉价的液滴?我们应该改为每月订阅高记忆液滴吗?如果我们使用自动旋转液滴,我们应该坚持使用 DigitalOcean 还是 Heroku 更有意义?或者整个方法是错误的,我们应该从一个完全不同的方向接近它吗?任何帮助/建议将不胜感激。

谢谢!

【问题讨论】:

【参考方案1】:

听起来您在 DigitalOcean 主机上可以运行的工作人员数量受到内存限制。

如果您担心扩展,我会专注于让工作人员尽可能高效。您是否做过任何基准测试来了解 900MB 内存的分配位置?我不确定这些工作的性质是什么,但你提到了大文件。您是将这些文件的内容读入内存,还是将它们流式传输?您是否正在使用可以调优的带有 SQL 的数据库?当您可以使用批处理端点时,您是否进行了许多小型 API 调用?您是否分配了必须进行垃圾收集的中间变量?您可以在发送之前压缩文件吗?

查看工作结构本身。我发现后台作业最适合许多较小的作业,而不是一项较大的作业。这允许执行并行发生,并在所有工作人员之间进行更多的负载平衡。你甚至可以拥有一份可以产生其他工作的工作。如果您需要在一组作业完成时编排回调,https://github.com/salsify/delayed_job_groups_plugin 有一个 DelayedJobGroup 插件,它允许您仅在同级作业完成后调用最终作业。我的目标是将单个作业的执行时间控制在 30 秒以下。这是任意的,但它说明了我所说的较小的工作是什么意思。

像亚马逊这样的一些托管服务提供商会提供 Spot 实例,您可以在这些实例中以较低的价格购买无法保证可用性的服务器。这些方法与我之前提到的少得多的工作方法相得益彰。

最后,Ruby 可能不是适合这项工作的工具。有更快的语言,如果你受到内存或 CPU 的限制,你可能会考虑用另一种语言(如 javascript、Go 或 Rust)编写这些作业及其工人。这些可以与 Ruby 堆栈很好地搭配,但将计算成本高昂的子例程转移到更快的语言。

最后,就像许多扩展问题一样,如果您的资金多于时间,您总是可以投入更多的硬件。至少有一段时间。

【讨论】:

感谢您的建议,本。我最终在 DO 上使用了一个高内存滴并启动了 50 个工作人员。我的想法是,随着我们的扩展,我可以租用更多的服务器。此外,内存消耗不正确。每个活动进程实际上更像是 250MB。【参考方案2】:

我觉得记忆和时间对你来说更成问题。你必须在这个过程中使用sidekiq gem,因为它会消耗更少的时间和内存消耗来做同样的工作,因为它使用redis作为数据库,它是键值对db。如果问题仍然存在,请使用java脚本。

【讨论】:

以上是关于在 Rails 中运行大量长时间运行的后台作业的主要内容,如果未能解决你的问题,请参考以下文章

在长时间运行的工作中防止更改

长时间运行的任务与线程——性能

iOS开发:后台运行以及保持程序在后台长时间运行

长时间运行的后台任务完成后应用程序未挂起

保持程序在后台长时间运行-b

如何在 AWS Elastic Beanstalk 上使用 Resque 运行 Rails 后台作业?