如何在Linux上用Ruby 2.0改善独angular兽进程之间的内存共享

Ruby 2.0引入了一个写时复制友好的垃圾收集器。 我的进程似乎并没有让内存共享超过几分钟 – 似乎很快就会从shared_dirty转移到private_dirty。

一些其他人已经成功地获得这个工作:

  • https://gist.github.com/kenn/5105175
  • http://marianposaceanu.com/articles/on-ruby-2-0-memory-usage-unicorn-and-heroku

这个程序可以用来检查Linux上的内存统计信息: https : //gist.github.com/kenn/5105061

我的麒麟configuration: https : //gist.github.com/inspire22/f82c77c0a465f1945305

出于某种原因,我的独angular兽应用程序,preload_app = true,共享内存也less得多。 Ruby 2.0-p195,rails 3.2,linux 2.6.18(centos)

[root@thorn script]# ruby memstats.rb 4946 Process: 4946 Command Line: unicorn_rails worker[4] -c /u/apps/newap/current/lib/unicorn.rb -E production -D Memory Summary: private_clean 0 kB private_dirty 56,324 kB pss 60,256 kB rss 83,628 kB shared_clean 4,204 kB shared_dirty 23,100 kB size 108,156 kB swap 68 kB 

如果我完全closures了主进程(不仅仅是一个HUP),然后重新启动它,并在任何请求排队之前立即检查一个工作者,我得到一个更好的故事:

 [root@thorn script]# ruby memstats.rb 5743 Process: 5743 Command Line: unicorn_rails worker[4] -c /u/apps/newap/current/lib/unicorn.rb -E production -D Memory Summary: private_clean 0 kB private_dirty 21,572 kB pss 27,735 kB rss 66,296 kB shared_clean 2,484 kB shared_dirty 42,240 kB size 91,768 kB swap 0 kB 

但在启动后的5秒钟内,他们又回到了〜20MB的shared_clean + shared_dirty。

我怀疑交换可能会导致这个问题,但是在降低swappiness并确保父进程和subprocess都没有交换(使用swapstats.rb)之后,问题依然存在。

我不明白什么shared_dirty内存,以及如何变成私人内存。 我也很乐意提高我的共享内存的寿命和数量。 谢谢!

根据你可能已经看到的这个答案 ,有一句话是这样写的:

请注意,“共享”页面被视为一个私有映射,直到它被实际共享。 即如果只有一个进程正在使用libfoo,则该库的文本部分将出现在进程的私有映射中。 只有当另一个进程开始使用该库时,才会将其logging在共享映射中(并从私有映射中删除)。

我会做什么来testing您是否获得了本文中概述的好处,将10MB xml文件作为文字string直接放入您的源代码中。 然后,如果您启动了20名工作人员,您将能够看到是否使用了200MB的内存,或者只有10MB,就像使用新的垃圾收集function所预期的那样。

更新:

我正在通过独angular兽的来源,并find了这个奇妙的文章的参考。

总而言之,为了适应您的应用程序,以便利用Ruby Enterprise Edition的写入时复制友好的垃圾回收器,您必须在分叉之前将GC.copy_on_write_friendly设置为true

 if GC.respond_to?(:copy_on_write_friendly=) GC.copy_on_write_friendly = true end 

根据您提供的独angular兽configuration文件​​,它似乎缺less分配。

另外,我喜欢阅读这些相关的文章:

根据叉子手册页 :

在Linux下,fork()是通过使用写时复制页面来实现的,所以唯一的代价就是复制父页表所需的时间和内存,并且创build一个独特的子任务结构。

从版本2.3.3开始 ,不是调用内核的fork()系统调用,而是作为NPTL线程实现的一部分提供的glibc fork()包装调用克隆(2),其标志提供了与传统系统调用相同的效果。 (调用fork()相当于调用clone(2)指定标志,就像SIGCHLD一样。)glibc包装调用已经使用pthread_atfork(3)build立的任何fork处理程序。

根据克隆手册页 :

与fork(2)不同,这些调用允许subprocess与调用进程共享部分执行上下文,如内存空间,文件描述符表和信号处理程序表。

所以,我正在阅读这个意思:linux的fork fork-copy-on-write,这是独angular兽依赖于实现内存共享的function,直到libc 2.2.3才能实现(请问,如果我错了,有人纠正我在这个解释中)。

要检查您运行的libc版本,可以键入:

 ldd --version 

或者,findglibc并直接运行。 在我的系统上,它在以下位置find该文件:

 locate libc.so /lib/x86_64-linux-gnu/libc.so.6