【问题标题】:using Kernel#fork for backgrounding processes, pros? cons?使用 Kernel#fork 作为后台进程,专业人士?缺点?
【发布时间】:2010-12-06 19:01:45
【问题描述】:

我想了解一下使用 fork{} 从 rails 应用程序“后台”处理进程是否是个好主意...

从我收集到的 fork{my_method; Process#setsid} 实际上做了它应该做的事情。

1) 创建另一个具有不同 PID 的进程

2) 不会中断调用过程(例如,它会继续等待 fork 完成)

3) 执行子进程直到它完成

..这很酷,但这是个好主意吗?叉子到底在做什么?它是否会在内存中创建我的整个 rails mongrel/passenger 实例的重复实例?如果是这样那将是非常糟糕的。或者,它是否以某种方式在不消耗大量内存的情况下做到这一点。

我的最终目标是取消我的后台守护程序/队列系统,转而支持分叉这些进程(主要是发送电子邮件)——但如果这不能节省内存,那么这绝对是朝着错误方向迈出的一步

【问题讨论】:

  • 我会坚持使用排队系统。如果您为此使用维护良好的软件包,则不必担心分叉炸弹攻击和良好排队系统所需的其他大量细节。在这种情况下,您应该小心滚动自己的代码,除非明确需要这样做。
  • 排队服务器++。可能想查看 MQ (github.com/mdarby/mq) 的电子邮件队列。我已经在生产环境中使用了几个月,没有任何问题。

标签: ruby-on-rails ruby background delayed-job backgroundrb


【解决方案1】:

fork 的语义是将进程的整个内存空间复制到一个新进程中,但是许多(大多数?)系统会通过复制虚拟内存表并将其标记为写时复制来做到这一点.这意味着(至少一开始)它不会使用更多的物理内存,只够制作新表和其他每个进程的数据结构。

也就是说,我不确定 Ruby、RoR 等与写时复制分叉的交互效果如何。特别是如果垃圾收集涉及许多内存页面(导致它们被复制),则可能会出现问题。

【讨论】:

  • 我听说过关于 COW 的两件事……很确定有些 1.8 分支不支持它,但 REE 支持(?)。而且我都听说过 1.9 支持和不支持 COW。也就是说,即使是这样,想象一下我的 rails 操作:def foo do_stuff fork_and_send_email do_more_stuff end 即使 fork COW 不会立即更改原始内存位置(因为之后发生的事情)和从而怂恿复制?即使 fork 是最后一个方法调用。我想 Rails 在它之后仍然会做一些事情,更不用说......下一个请求在同一个过程中进入。
  • 见鬼,评论格式:def foo;做东西; fork_and_send_email; do_more_stuff;结束
  • 嗯,是的,会发生一些复制,但希望它不会是进程的整个内存空间;而是到处都是单独的内存页面(在 x86 内存页面上通常是 4 KB)。
  • 等一下,COW 是操作系统内核提供给所有东西的东西,它不依赖于应用程序版本,是的,它是逐页的,所以一次写入只会触发一个副本页面
【解决方案2】:

fork 确实会复制您的整个流程,并且根据您连接到应用程序服务器的确切方式,也会复制该流程。正如在其他讨论中所指出的,这是通过 copy-on-write 完成的,所以它是可以容忍的。毕竟,Unix 是围绕 fork(2) 构建的,所以它必须相当快地管理它。请注意,任何部分缓冲的 I/O、打开的文件和许多其他内容也会被复制,以及弹簧加载以将它们写出的程序状态,这是不正确的。

我有几个想法:

  • 您在使用 Action Mailer 吗?似乎使用 AM 或 Process.popen 可以轻松完成电子邮件。 (Popen 会做一个 fork,但紧接着是一个 exec。)
  • 通过执行另一个 ruby​​ 解释器的 Process.exec 以及您的功能,立即摆脱所有这些状态。如果要传输的状态太多,或者您确实需要使用那些重复的文件描述符,您可能会执行IO#popen 之类的操作,这样您就可以发送子进程的工作去做。系统会自动与父进程共享包含子进程Ruby解释器文本的页面。
  • 除了上述之外,您可能还需要考虑使用daemons gem。虽然您的 rails 进程已经是一个守护进程,但使用 gem 可以更轻松地保持一个后台任务作为批处理作业服务器运行,并使其易于启动、监控、在它发生故障时重新启动以及在您执行时关闭。 .
  • 如果您确实退出了fork(2)ed 子进程,请使用exit! 而不是exit
  • 已经设置了一个消息队列和一个守护进程,就像你一样,对我来说听起来是一个不错的解决方案 :-)

【讨论】:

    【解决方案3】:

    请注意,它会阻止您使用 JRuby on Rails,因为 fork() 尚未实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-02
      • 2010-11-27
      • 2013-02-24
      • 2022-11-02
      • 1970-01-01
      • 2013-08-07
      • 2015-12-31
      • 1970-01-01
      相关资源
      最近更新 更多