- 浏览: 4836362 次
- 性别:
- 来自: 上海
-
博客专栏
-
-
robbin谈管理
浏览量:138034
文章分类
最新评论
-
xly1981:
领导者是团队的灵魂。深入一线的过程,包括代码review,能帮 ...
robbin谈管理:改造团队的经验(2) -
jiehuangwei:
像这种总结比较性的ppt文档可以多发啊
Web并发模型粗浅探讨 -
linux1308:
看完学习到了很多东西,感谢推荐!
推荐一篇很好的RoR部署方案性能评测 -
zweite:
直接对搜索的结果进行缓存是不是会更快一点呢
漫谈应用缓存的命中率问题 -
kaogua:
现在已经是ruby2.0了, 不知道这个的效率是怎么样的, 是 ...
Ruby作为服务器端应用已经成熟了
Ruby虽然是动态脚本语言,但是和Java一样,带有VM,有自己的内存堆,创建对象的时候在堆里面分配内存,对象使用完毕由GC进行回收。但是通过我们运营Rails网站两年多的实践来看,Ruby VM的GC还是存在很大的问题。简单的来说,就是GC之后,尽管对象已经完全回收,但是物理内存释放不够充分,有泄漏的现象。通过pmap来dump ruby进程物理内存地址映射表进行分析,观察到ruby的内存堆总是在不停的扩张,GC之后回收不干净。而我对比观察Java VM,其Full GC之后,物理内存释放的非常干净。所以用Ruby做服务器长期的跑,就会发现Ruby进程没有理由的缓慢泄漏内存,内存堆缓慢增长,貌似没有上限。
由于pmap命令可以dump进程的内存映射表,因此我们可以对比RubyVM和JVM在GC前后的内存映射情况。比方说Ruby的内存状况大概是这样的:
下图是一个Ruby进程的物理内存映射表,堆内存占据的空间是我抽取出来的三行:
可以看出来Ruby的堆内存分配比较连续,分段不多。而JVM的堆内存分配段就很多了,由于堆地址段太多,我就不贴出来了,大家可以自己观察。
由于Ruby的内存分配算法和回收算法还是比较原始的,因此在进行多次回收之后,内存堆很容易出现大量的内存碎片,很多内存碎片并不能够被有效的利用,并且ruby没有好的碎片归并压缩算法,因此碎片造成的内存堆地址空间浪费就会越来越大。其结果就是Ruby进程在长期高负载运行之下,表现出缓慢的内存泄漏现象!
对比JVM的堆分配,他分配了很多的段,每个段的内存存活期不一样,根据分代算法,可以把不同存活期的对象在堆之间移动,堆内部则进行碎片归并。比方说我对一个Tomcat应用服务器的实际应用先pmap记录内存映射,然后GC,再pmap记录内存映射,两者diff一下,就可以发现某些堆在收缩,但是某些堆甚至在GC后扩张了,这便是对象在堆之间进行移动的现象。因此我不得不赞赏一下JVM的内存分配。
话说回来,由于Ruby的VM内存分配的碎片问题,导致Ruby进程几乎无可避免的内存泄漏。其结果就是你必须实时监控Ruby进程的运行情况,一旦发现内存使用超过限额,则必须果断的杀掉进程重起。比方说现在很多流行的Rails网站都是用monit去监控mongrel实例,一旦发现内存使用超过限额就杀掉重起。这种监控方式虽然可以有效的解决ruby的内存泄漏问题,但是太过简单粗暴,如果杀掉进程重起的时候,Ruby进程正好在处理请求,那么该请求是肯定会失败掉的,对于一些极端的情况,似乎很难令人接受这种现象的存在。我现在没有用monit,而是自己写shell脚本来监控(写几行shell就可以搞定的事情没必要那么麻烦搞什么monit),每天大概能出现两三次这种需要杀掉重起的情况,对比每天要处理将近100 万动态请求来说,可靠性还是达到了99.999%,还算可以。
那么将于今年年底发布的ruby 1.9.1能够解决这个问题吗? 答案是悲观的,1.9的GC并没有本质的提高,可以预见还是会出现无可避免的内存泄漏问题。但是1.9的内存泄漏会比现在的1.8要轻微一些,原因是1.9会对堆空间的内存碎片从小到大进行排序,因此对于内存碎片的利用率要高一些,再加上1.9的GC相对来说更积极主动一些,因此在一定程度上可以减轻内存碎片问题。
但不管怎么说,在可以预见的未来,Ruby的内存泄漏问题无可避免,我们还是要做好动不动杀掉ruby进程重起的准备。所以你要好好操练一下monit,或者像我一样,写个shell脚本进行监控,用crontab每隔几分钟跑一下。
我们的Rails部署方式是lighttpd+fcgi,用Unix Socket通信,监控脚本示例如下:
之前有关注过这个VM,看FAQ不能在64位系统上运行,而我们目前网站是运行在64位操作系统上。
这个VM配合mod_rails比较合适用来做虚拟主机提供rails host服务
而Rails 2.2的线程安全也应该有这方面的考虑
找个时间试试Ruby Enterprise Editio,谢谢推荐。
由于pmap命令可以dump进程的内存映射表,因此我们可以对比RubyVM和JVM在GC前后的内存映射情况。比方说Ruby的内存状况大概是这样的:
下图是一个Ruby进程的物理内存映射表,堆内存占据的空间是我抽取出来的三行:
00000000005d4000 125260K rwx-- [ anon ] 0000002a95c23000 23456K rw--- [ anon ] 0000002a99186000 50980K rw--- [ anon ]
0000000000400000 760K r-x-- /usr/local/ruby/bin/ruby 00000000005bd000 92K rw--- /usr/local/ruby/bin/ruby 00000000005d4000 125260K rwx-- [ anon ] 0000002a95556000 84K r-x-- /lib64/ld-2.3.3.so 0000002a9556b000 12K rw--- [ anon ] 0000002a9556e000 24K r--s- /usr/lib64/gconv/gconv-modules.cache 0000002a95574000 4K rw--- [ anon ] 0000002a95577000 12K rw--- [ anon ] 0000002a9557a000 204K r---- /usr/lib/locale/en_US.utf8/LC_CTYPE 0000002a9566a000 12K rw--- /lib64/ld-2.3.3.so 0000002a9566d000 8K r-x-- /lib64/libdl.so.2 0000002a9566f000 1024K ----- /lib64/libdl.so.2 0000002a9576f000 4K rw--- /lib64/libdl.so.2 ......
可以看出来Ruby的堆内存分配比较连续,分段不多。而JVM的堆内存分配段就很多了,由于堆地址段太多,我就不贴出来了,大家可以自己观察。
由于Ruby的内存分配算法和回收算法还是比较原始的,因此在进行多次回收之后,内存堆很容易出现大量的内存碎片,很多内存碎片并不能够被有效的利用,并且ruby没有好的碎片归并压缩算法,因此碎片造成的内存堆地址空间浪费就会越来越大。其结果就是Ruby进程在长期高负载运行之下,表现出缓慢的内存泄漏现象!
对比JVM的堆分配,他分配了很多的段,每个段的内存存活期不一样,根据分代算法,可以把不同存活期的对象在堆之间移动,堆内部则进行碎片归并。比方说我对一个Tomcat应用服务器的实际应用先pmap记录内存映射,然后GC,再pmap记录内存映射,两者diff一下,就可以发现某些堆在收缩,但是某些堆甚至在GC后扩张了,这便是对象在堆之间进行移动的现象。因此我不得不赞赏一下JVM的内存分配。
话说回来,由于Ruby的VM内存分配的碎片问题,导致Ruby进程几乎无可避免的内存泄漏。其结果就是你必须实时监控Ruby进程的运行情况,一旦发现内存使用超过限额,则必须果断的杀掉进程重起。比方说现在很多流行的Rails网站都是用monit去监控mongrel实例,一旦发现内存使用超过限额就杀掉重起。这种监控方式虽然可以有效的解决ruby的内存泄漏问题,但是太过简单粗暴,如果杀掉进程重起的时候,Ruby进程正好在处理请求,那么该请求是肯定会失败掉的,对于一些极端的情况,似乎很难令人接受这种现象的存在。我现在没有用monit,而是自己写shell脚本来监控(写几行shell就可以搞定的事情没必要那么麻烦搞什么monit),每天大概能出现两三次这种需要杀掉重起的情况,对比每天要处理将近100 万动态请求来说,可靠性还是达到了99.999%,还算可以。
那么将于今年年底发布的ruby 1.9.1能够解决这个问题吗? 答案是悲观的,1.9的GC并没有本质的提高,可以预见还是会出现无可避免的内存泄漏问题。但是1.9的内存泄漏会比现在的1.8要轻微一些,原因是1.9会对堆空间的内存碎片从小到大进行排序,因此对于内存碎片的利用率要高一些,再加上1.9的GC相对来说更积极主动一些,因此在一定程度上可以减轻内存碎片问题。
但不管怎么说,在可以预见的未来,Ruby的内存泄漏问题无可避免,我们还是要做好动不动杀掉ruby进程重起的准备。所以你要好好操练一下monit,或者像我一样,写个shell脚本进行监控,用crontab每隔几分钟跑一下。
我们的Rails部署方式是lighttpd+fcgi,用Unix Socket通信,监控脚本示例如下:
#!/bin/sh . /etc/profile.local RUBY_HEAP_MIN_SLOTS=600000 RUBY_HEAP_SLOTS_INCREMENT=600000 RUBY_HEAP_FREE_MIN=100000 RUBY_GC_MALLOC_LIMIT=60000000 RAILS_ENV=production export RUBY_HEAP_MIN_SLOTS RUBY_HEAP_SLOTS_INCREMENT RUBY_GC_MALLOC_LIMIT RUBY_HEAP_FREE_MIN RAILS_ENV SPAWN=/usr/local/lighttpd/bin/spawn-fcgi DISPATCH_PATH=/.../yourrailsapp/public/dispatch.fcgi SOCKET_PATH=/yourlighttpd/socket PID_PATH=/yourlighttpd/pids RSS_MAX=307200 for PSDATA in `ps -e v | grep dispatch.fcgi | awk '{print $1 ":" $8 }'` do RSS=${PSDATA#*:} PID=${PSDATA%:*} if [ $RSS -ge $RSS_MAX ]; then echo echo `date` echo "----------------------------------------" echo "PID["$PID"]: RSS="$RSS"KB is too big!" for num in 0 1 2 3 4 5 6 7 8 9 do if [ $PID -eq `cat $PID_PATH/javaeye.pid-$num` ]; then echo "PID["$PID"] using socket: "$num kill -9 $PID rm -rf $SOCKET_PATH/javaeye.socket-$num $SPAWN -f $DISPATCH_PATH -s $SOCKET_PATH/javaeye.socket-$num -P $PID_PATH/javaeye.pid-$num fi done fi done sleep 10 for num in 0 1 2 3 4 5 6 7 8 9 do if [ ! -d /proc/`cat $PID_PATH/javaeye.pid-$num` ]; then echo echo "Ruby Server using socket: "$num" had been crashed, need to be starting..." rm -rf $SOCKET_PATH/javaeye.socket-$num $SPAWN -f $DISPATCH_PATH -s $SOCKET_PATH/javaeye.socket-$num -P $PID_PATH/javaeye.pid-$num fi done
评论
11 楼
sevk
2012-01-19
JAVA开源不,把JAVA的GC移植到RUBY里来。
linux就是好,可以像组装机一样自己选择GC。
java的thread也不错,也可以鉴戒,开源就是好。
linux就是好,可以像组装机一样自己选择GC。
java的thread也不错,也可以鉴戒,开源就是好。
10 楼
liangshixing
2008-11-23
为什么不用JRuby呢?
9 楼
chengj
2008-09-09
ruby要进入企业级的应用还有很长的一段路要走。使用ROR开发的感觉确实畅快,但是现在不得不退回到java,虽然心有不甘,但是没有办法,先观望一段时间,希望ruby走好。
8 楼
t0uch
2008-09-05
按mod_rails的作者来说
改进是很明显的
但是,近来想把这个gc算法patch到ruby core搞定似乎是很困难了
改进是很明显的
引用
This has huge performance implications. The copy-on-write friendly mark table makes the garbage collector about 0%-20% slower, depending on the application and the workload. However, the non-copy-on-write friendly mark table is enabled by default, so by default there is only a 1% performance penalty. This performance penalty comes from the fact that marking an object now requires a function call which sets the mark flag, instead of setting the mark flag directly. But I think 1% is acceptable.
但是,近来想把这个gc算法patch到ruby core搞定似乎是很困难了
引用
Unfortunately the discussion stranded. Matz had some concerns about performance, which is why I made the mark table implementation pluggable. I will re-submit the patch for further evaluation when the time is right.
7 楼
leondu
2008-09-05
嗯,你说的这个就是Enterprise Ruby(很雷的名字...他们也说要选个更适合的名字),Matz说“考虑”加入到core中,但是好像没下文了。
pluskid 写道
phusion passenger (mod_rails) 的作者好像就做过改进 GC 的工作,也提交了一些补丁到 Ruby core 。不知道改进明显不明显。
6 楼
pluskid
2008-09-03
phusion passenger (mod_rails) 的作者好像就做过改进 GC 的工作,也提交了一些补丁到 Ruby core 。不知道改进明显不明显。
5 楼
QuakeWang
2008-09-03
yawl 写道
mod_rails的作者也做了个Ruby Enterprise Editio (http://www.rubyenterpriseedition.com/ ),基本上就是改进了GC.用了一阵子了一直很稳定,但我们的流量流量都没有javaeye这么大.
之前有关注过这个VM,看FAQ不能在64位系统上运行,而我们目前网站是运行在64位操作系统上。
引用
Ruby Enterprise Edition is a bit faster than standard Ruby, because of the improved memory allocator. However, this memory allocator does not work on 64-bit platforms. As a result, on 64-bit platforms, Ruby Enterprise Edition is slightly slower than standard Ruby (by a few percent). How much slower depends on the application and workload.
这个VM配合mod_rails比较合适用来做虚拟主机提供rails host服务
而Rails 2.2的线程安全也应该有这方面的考虑
4 楼
robbin
2008-09-03
yawl 写道
mod_rails的作者也做了个Ruby Enterprise Editio (http://www.rubyenterpriseedition.com/ ),基本上就是改进了GC.用了一阵子了一直很稳定,但我们的流量流量都没有javaeye这么大.
我的一个做JVM的朋友按照JVM的实现也重写过ruby gc,效果也很好.但只能限于proof of concept,没有时间和经历去雕琢.
我的一个做JVM的朋友按照JVM的实现也重写过ruby gc,效果也很好.但只能限于proof of concept,没有时间和经历去雕琢.
找个时间试试Ruby Enterprise Editio,谢谢推荐。
3 楼
yawl
2008-09-03
mod_rails的作者也做了个Ruby Enterprise Edition (http://www.rubyenterpriseedition.com/ ),基本上就是改进了GC.用了一阵子了一直很稳定,但我们的流量都没有javaeye这么大.
我的一个做JVM的朋友按照JVM的实现也重写过ruby gc,效果也很好.但只能限于proof of concept,没有时间和经历去雕琢.
我的一个做JVM的朋友按照JVM的实现也重写过ruby gc,效果也很好.但只能限于proof of concept,没有时间和经历去雕琢.
2 楼
iceskysl
2008-09-03
RSS_MAX=307200
--这个值是哪里得来的?经验?
--这个值是哪里得来的?经验?
1 楼
iceskysl
2008-09-03
简单粗暴是针对问题最直接的解决办法。
发表评论
-
《松本行弘的程序世界》推荐序
2011-07-21 13:47 15371在流行的编程语言中,ruby是一个比较另类的存在,这是因为大多 ... -
从Rails聊聊小公司的研发团队建设
2011-03-23 10:49 37296首先分享一点数据吧: JavaEye的PV到了140万了,一 ... -
Ruby作为服务器端应用已经成熟了
2009-11-17 14:55 16097JavaEye网站在过去的Ruby on rails实践当中, ... -
基于资源的HTTP Cache的实现介绍
2009-09-05 00:27 17144我们都知道浏览器会缓 ... -
请注意Rails2.3自带的memcache-client有性能问题
2009-03-23 18:05 14611Rails2.3版本发布了,这个版本内部的改动非常大,相关介绍 ... -
监视Rails进程内存泄漏的技巧
2008-12-30 21:56 11029Rails应用比较容易遇到的两类性能问题:一类是Rails执行 ... -
ruby MBARI大补丁性能评测报告
2008-12-23 12:19 5113JavaEye之前的新闻ruby内存泄漏的罪魁祸首 - 幽灵指 ... -
在top监视窗口显示Rails当前正在执行的请求URL
2008-12-01 14:15 9919这是一个从PragDave的博客上面学来的技巧,很实用,很co ... -
推荐一篇很好的RoR部署方案性能评测
2008-07-08 11:55 9764今年年初的时候,我写了一篇RoR部署方案深度剖析的文章,分析了 ... -
Ruby和Rails的缺点
2008-06-25 21:08 17486有人说,robbin你说了那么多RoR的优点,你啥时候说说Ro ... -
Skynet --- ruby的类Google Map/Reduce框架
2008-06-02 00:39 8348Skynet是一个很响亮的名 ... -
rmmseg-cpp - 简洁高效的ruby中文分词程序
2008-05-27 00:47 11287我在前一篇文章向大家 ... -
使用libmmseg实现Ruby的中文分词功能
2008-05-24 21:43 11373用Ruby on Rails开发web2.0网站的人都知道,r ... -
mod_rails尝鲜
2008-04-13 14:32 8121Passenger(俗称mod_rails)是 ... -
Lighttpd和RoR安装配置的疑难解答
2008-03-07 11:09 14919之前写过一篇在Linux平 ... -
JavaEye网站的RoR性能优化经验谈
2008-01-20 16:11 18526JavaEye网站从2006年9月11 ... -
RoR部署方案深度剖析
2008-01-14 03:10 14876RoR的部署方案可谓五花八门,有Apache/Fastcgi方 ... -
RoR网站如何利用lighttpd的X-sendfile功能提升文件下载性能
2008-01-12 17:45 10339传统的Web服务器在处理文件下载的时候,总是先读入文件内容到应 ... -
Ruby为什么会受程序员的欢迎?
2008-01-07 20:08 15797孟岩最近写了一篇博客 ... -
Ruby on Rails 2.0的新特性介绍
2007-12-10 21:32 15675万众瞩目的Ruby on Rails 2.0已经发布了,Rai ...
相关推荐
1. **YARV虚拟机优化**:Ruby 2.6.1基于YARV(Yet Another Ruby VM)虚拟机,这个版本对YARV进行了优化,提高了整体性能,尤其是对于CPU密集型的任务。 2. **编译器优化**:Ruby 2.6引入了新的编译器框架,使得语法...
8. **YARV虚拟机优化**:Ruby 2.0继续使用YARV(Yet Another Ruby VM)作为其虚拟机,但进行了多方面的优化,提高了整体性能。 压缩包内的"ruby-2.0.0-p0"可能包含了完整的Ruby解释器、标准库、开发工具以及相关的...
在性能方面,Ruby 2.2.4增强了YARV(Yet Another Ruby VM)虚拟机,提升了代码执行速度。同时,它还修复了一些已知的安全漏洞,提高了整体的系统稳定性。 Ruby 2.2.4还支持新的语法特性,如Numeric Literal Ranges...
首先, Rubinius 包含了一个虚拟机(VM),它是执行Ruby代码的基础。虚拟机设计的目标是解析并执行Ruby的字节码,这使得Ruby程序能够在不同的平台上运行,而无需针对每个平台重新编译。这个虚拟机的设计是高度优化的...
包括更快的字典查找,更高效的垃圾回收机制,以及对Ruby VM的其他内部改进。 10. **Ruby的版本管理(Ruby Version Manager)** Ruby 2.0发布的同时,rvm(Ruby Version Manager)和rbenv等版本管理工具也得到了...
特征安装在正在运行的应用程序中的Web仪表板Rails常规配置,包括默认值库和框架的运行时内部(例如ActiveRecord查询缓存) 控制器和模型的应用清单宝石装Ruby VM运行时信息(GC统计信息,调整参数) 可选的分析...
在使用jprofiler时,我们可以在VM arguments中加入这些参数,包括JRuby的配置选项,例如: - `-server`:指定使用服务器版本的JVM,优化性能。 - `-Xmx378m`:设置最大堆内存为378MB。 - `-Xss1024k`:设置每个线程...
1. **改进的编译器** - JDK 1.6中的编译器,也称为HotSpot VM,进行了优化,提供了更快的代码生成和更高效的运行时性能。它增强了类型推断,使得Java语言在处理泛型时更加智能。 2. **动态语言支持** - JDK 1.6引入...