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

我们正在诊断我们的应用程序服务器上的Ruby性能问题,我们已经设法减less到一个简单的testing用例。

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

我们使用这个简单的Ruby oneliner:

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

而我们的testing结果表明,生产机器的速度一直慢了55%。

事情显然可能是,为什么我们认为这不是:

  1. 不同的软件 – 开发和生产机器是从相同的Ubuntu OS,Ubuntu安装脚本,软件包仓库安装的,我们使用puppet来保持configuration的一致性。
  2. 不同的硬件 – 可能,但见下文。
  3. 不同的负载 – 既不是开发也不是生产机器显着加载,并再次看到下面。

为什么我们不认为它是负载或硬件?

首先,他们有类似的负载和硬件configuration。 其次,我们写了一个pythontesting脚本:

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

生产速度比开发速度快 10%,这是我们所期望的。 如果问题是负载或硬件,那么Python的生产速度是不是会变慢呢?

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

  • 开发虚拟机有4GB内存,并在双核四核AMD Opteron 2376 @ 2.294Ghz 32GB的机器上提供一个虚拟内核的虚拟机

  • 生产虚拟机具有4GB内存,并在双核四核AMD Opteron 2354 @ 2.211Ghz 32GB的机器上提供四个虚拟内核的虚拟机(更新:我们现在已经尝试了所有虚拟机上的一个虚拟内核,没有什么区别)

操作系统是Ubuntu Hardy 64bit。 我们的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) 

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

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

  • Opteron 2354拥有2MB的L-3caching,其中2376拥有6MB。
  • 2354使用PC2-5300 DDR2 RAM,2376使用PC2-6400 DDR2 RAM。

我用硬件有些生疏,但是我认为这意味着开发机器上的内存访问总体来说要快得多? 所以,如果Ruby在某种程度上更多的是“内存密集型”(我并不真正了解我的意思!),那么它可能会performance出更大的性能差异?

(我去查看是否在新的处理器中有一些虚拟化function可以解释这种差异,但是空白。)

几个问题…

  • 每个服务器上的其他虚拟机在做什么?
  • 你看到与另一个(不是基于MRI的)Ruby,JRuby可能相同的行为?
  • 你能用ltrace / strace运行样本,看看在哪里花了时间吗? 请参阅debuggingRuby:了解和排除虚拟机和您的应用程序以获取更多详细信息。

你有没有试过减less你给生产虚拟机的vCPU数量?

我知道这听起来会适得其反,而且您可能已经意识到这一点,如果分配给任何给定虚拟机的所有vCPU插槽都不空闲,ESX将不会给予任何CPU时间 – 即,如果虚拟机有4个vCPU分配到了它,他们只是不全是免费的,然后虚拟机根本没有任何的时间。 我知道这听起来很精神,但是认真的试着放到2个或1个vCPU并再次运行。

祝你好运。

其实这也是我正在考虑的途径。 由于生产服务器上的caching较小,因此耗尽速度更快,不得不使用主内存。 如果这种访问在生产中比开发慢,这可能会导致问题。

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

总之,我还在寻找!

问:你如何做标杆? 你使用ruby的基准ruby版本或外部工具? 如果前者,我想知道是否是在基准库中的东西造成的问题。

我上周在我们的系统上也遇到了类似的问题。 原来是因为有人安装了/需要主动支持,这个主动支持正在修改我们课程堆栈里的一堆东西,并且造成了一个放缓。 只有在针对实际stream量运行时才会检测到 检查慢速系统上已安装的gem,并将其与开发机器进行比较。 它有可能是出了什么问题。

我通常不信任VMWare的性能,所以如果他们都是相同的vmwareconfiguration,会非常感兴趣的看看会发生什么。

呃…只是为了确定,当你这样做的时候会发生什么:

  n = 1000000 while n > 1 do n = n - 1 a = [] a.push 4 a.length end 

我知道它的function等同于1000000.times { a = []; a << 4; a.length } 1000000.times { a = []; a << 4; a.length } 1000000.times { a = []; a << 4; a.length } ,但是时代的function可能会在幕后做些时髦的事情呢? 我也同意关于线程的说法,但这实际上意味着开箱速度只有0.083Ghz–这不太可能造成55%的下降。 看看ruby 1.9是什么会很有趣,但是如果你已经尝试过稀土元素,我怀疑性能差异会太大。 我假设它是完全相同的磁盘速度,内存caching等?

难道是因为ruby无法利用额外的虚拟核心由于绿色线程,而本地线程的python可以吗? (野驴在这里猜 – 我真的不知道我在说什么)。