解释这个奇怪的与环境相关的 Ruby 性能问题

解释这个奇怪的与环境相关的 Ruby 性能问题

我们正在诊断应用程序服务器上的 Ruby 性能问题,并将其简化为一个简单的测试用例。

我们将开发集群中的机器与生产数据中心中的机器的性能进行比较。

我们使用了下面这个简单的 Ruby 单行程序:

5000000.times { a = []; a << 1; a.length }

我们对其进行了基准测试,结果显示其在生产机器上的速度始终慢了 55%。

显然可能存在的情况以及我们认为不可能存在的情况:

  1. 不同的软件 - 开发和生产机器从相同的 ubuntu 操作系统、ubuntu 安装脚本、软件包存储库安装,并且我们使用 puppet 来保持配置一致。
  2. 不同的硬件 - 可能,但请参见下文。
  3. 不同的负载——开发机器和生产机器都没有显著的负载,再次参见下文。

我们为什么不认为这是负载或者硬件的问题呢?

首先,它们的负载和硬件配置都差不多。其次,我们编写了一个python测试脚本:

n = 10000000
while n > 1:
  n = n - 1
  a = []
  a.append(4)
  len(a)

并且这个数字始终是 10%快点生产速度比开发速度快,这也是我们所期望的。如果问题出在负载或硬件上,Python 在生产速度上不是也会更慢吗?

简而言之,两台机器都使用 ESXi 进行虚拟化

  • 开发虚拟机具有 4GB RAM,并托管在具有双四核 AMD Opteron 2376 @ 2.294Ghz 32GB 的机器上,为虚拟机提供一个虚拟核心

  • 生产虚拟机具有 4GB RAM,并托管在具有双四核 AMD Opteron 2354 @ 2.211Ghz 32GB 的机器上,为虚拟机提供四个虚拟核心(更新:我们现在已在所有虚拟机上尝试使用一个虚拟核心,但没有任何区别)

操作系统是 Ubuntu Hardy 64位。我们的 Ruby 解释器是:

ruby 1.8.6 (2008-08-11 patchlevel 287) [x86_64-linux]

我们的 Python 解释器是

Python 2.5.2 (r252:60911, Jul 31 2008, 17:31:22)

注意:我们也尝试过使用 Ruby Enterprise Edition,结果是一样的。

答案1

我不知道发生了什么,但我想分享一些基于处理器的其他硬件差异,看看是否可以帮助其他人更接近答案。

  • Opteron 2354 具有 2MB L-3 缓存,而 2376 具有 6MB。
  • 2354 使用 PC2-5300 DDR2 RAM,而 2376 使用 PC2-6400 DDR2 RAM。

我对硬件不太熟悉,但我认为这意味着内存访问在开发机器上通常要快得多?那么,如果 Ruby 在某种程度上更加“占用大量内存”(我真的不知道我的意思!),那么它是否会表现为更大的性能差异?

(我曾寻找过新处理器中是否有一些虚拟化功能可以解释这种差异,但却一无所获。)

几个问题...

  • 每台服务器上的其他虚拟机在做什么?
  • 您是否看到另一个(不是基于 MRI 的)Ruby、可能是 JRuby 有同样的行为?
  • 您可以使用 ltrace/strace 运行示例,看看时间都花在了哪里?请参见调试 Ruby:理解并排除 VM 和应用程序故障更多细节。

答案2

您是否尝试过减少提供给生产虚拟机的 vCPU 数量?

我知道这听起来适得其反,但您可能已经意识到了这一点,如果分配给任何给定 VM 的所有 vCPU 插槽都不空闲,ESX 将不会为 VM 提供任何 CPU 时间 - 即,如果分配给 VM 的 4 个 vCPU 并非全部空闲,则 VM 根本无法获得任何时间。我知道这听起来很疯狂,但请认真尝试降至 2 个或 1 个 vCPU 并再次运行它。

祝你好运。

答案3

实际上这也是我考虑的办法。由于生产服务器上的缓存较小,因此会更快耗尽缓存,不得不使用主内存。如果生产中的访问速度比开发中慢,则这可能是问题所在。

但是,同样的问题也会发生在 Python 上。由于 Ruby 和 Python 都是用 C 实现的,因此整数大小可能相同(不过这个假设可能是错误的)。

总之我还在寻找!

答案4

上周我在我们的系统上遇到了类似的问题。原来是因为有人安装/要求使用 activesupport,它修改了我们类堆栈中的一堆内容,从而导致速度变慢。只有在实际流量下运行时才会检测到这个问题。检查慢速系统上安装的 gem,并将版本与开发机器进行比较。可能有些地方出了问题。

相关内容