13

我有一个 ruby​​ on rails 应用程序。我正在调查我的 NewRelic 门户中的 Apdex 下降,我看到平均 250-320 毫秒的时间用于 GC 执行。这是一个非常令人不安的数字。我在下面包含了一个屏幕截图。

我的 Ruby 版本是:

ruby 1.9.3p194(2012-04-20 修订版 35410)[x86_64-linux]

任何调整这个的建议都是理想的。这个数字应该大大降低。

在此处输入图像描述

4

4 回答 4

10

您在 GC 上花费了很多时间,因为您经常运行 GC。默认情况下,Ruby 设置适用于小型脚本而非大型应用程序的 GC 参数。尝试使用以下环境参数集启动您的应用程序:

RUBY_HEAP_MIN_SLOTS=800000
RUBY_FREE_MIN=100000
RUBY_GC_MALLOC_LIMIT=79000000

这将做的是增加初始堆分配大小并填充 GC 编号,以便它不会经常运行。这可能会让你的应用程序使用更多的 RAM,但它应该会显着减少花费在 GC 上的时间。在默认设置下,您可能会在每个请求中多次运行 GC;理想情况下,您希望每隔几个请求运行一次(或者更好的是,在使用Unicorn 的 OOB::GC 之类的请求之间)。

这些是我的应用程序的 GC 设置,您需要上下调整它们以最适合您的应用程序以找到正确的设置;你正在寻找一个中间地带,你不经常运行 GC,并且没有过多的内存使用。但是,这是针对每个应用程序的,因此对于这些确切设置应该是什么,我无法给出样板建议。从默认值(10k 个插槽,1.8 倍增长因子)增加应该会立即产生影响,您可以从那里上下调整以最适合您当前的情况。

这里有这些参数的完整记录和更多信息虽然这些帖子是为 REE 1.8.7 编写的,但它们也适用于 Ruby 1.9.2+。

这些是一些相当极端的数字,因此您可能正在应用程序中执行某些操作,导致您分配的 RAM 比应有的多得多,因此我鼓励您保持怀疑并梳理您的应用程序以寻找过度 -急切的分配。不过,GC 环境变量在任何情况下都应该有助于对情况进行分类。

于 2012-11-18T19:24:00.820 回答
0

您应该使用分配跟踪器来找出您的代码在哪里分配对象,以及分配对象的数量。我过去使用memprof过,效果很好……最大的缺点是它只能在 Ruby 1.8 下工作(希望你的代码与 1.8.7 兼容)。

如果您可以在 Ruby 1.8.7 下运行您的应用程序,则安装“memprof”gem,然后:

require 'memprof'
GC.disable
Memprof.track { run_test_code_here }

这会将已分配对象计数的列表(按类和分配发生的源行分组)打印到标准输出。

当您在垃圾收集器中花费过多时间时遇到问题,分配跟踪通常会显示您的程序分配大量对象的一两个地方。不可能提前说出解决方案是什么,但通常会涉及:

  1. 缓存结果以避免重复计算,
  2. 在安全的情况下使用破坏性操作(例如map!代替map),
  3. 在循环中重用临时对象(每次重置其状态)而不是在每次迭代时分配一个新对象,或
  4. 避免在多次执行的循环中使用字符串常量(或数组/哈希字面量)(每次迭代都会分配一个新对象)。
于 2012-11-18T19:33:07.837 回答
0

还有这个小技巧,它可能会起作用。但是更大的应用程序往往会分配如此大量的内存,以至于您每次请求都会杀死一个工作人员:-/

于 2012-11-18T23:42:16.713 回答
0

假设您没有错误地创建不需要的对象,我听说一种 hack/解决方案(除了使用 JRuby)是在完成发送响应后强制进行 GC。这样你就有了很大的停顿,但请求的消费者看不到它。如果你有这么多垃圾,你会看到像这样的多次停顿,那么你可能不走运。

这个技巧可能会也可能不会满足您的需求。

-JRuby 与有 MRI GC 问题的人交谈的人 :)

于 2012-11-25T17:32:39.473 回答