- 浏览: 4798286 次
- 性别:
- 来自: 上海
博客专栏
-
robbin谈管理
浏览量:135701
文章分类
最新评论
-
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 15060在流行的编程语言中,ruby是一个比较另类的存在,这是因为大多 ... -
从Rails聊聊小公司的研发团队建设
2011-03-23 10:49 37076首先分享一点数据吧: JavaEye的PV到了140万了,一 ... -
Ruby作为服务器端应用已经成熟了
2009-11-17 14:55 15769JavaEye网站在过去的Ruby on rails实践当中, ... -
基于资源的HTTP Cache的实现介绍
2009-09-05 00:27 16958我们都知道浏览器会缓 ... -
请注意Rails2.3自带的memcache-client有性能问题
2009-03-23 18:05 14274Rails2.3版本发布了,这个版本内部的改动非常大,相关介绍 ... -
监视Rails进程内存泄漏的技巧
2008-12-30 21:56 10855Rails应用比较容易遇到的两类性能问题:一类是Rails执行 ... -
ruby MBARI大补丁性能评测报告
2008-12-23 12:19 5010JavaEye之前的新闻ruby内存泄漏的罪魁祸首 - 幽灵指 ... -
在top监视窗口显示Rails当前正在执行的请求URL
2008-12-01 14:15 9777这是一个从PragDave的博客上面学来的技巧,很实用,很co ... -
推荐一篇很好的RoR部署方案性能评测
2008-07-08 11:55 9492今年年初的时候,我写了一篇RoR部署方案深度剖析的文章,分析了 ... -
Ruby和Rails的缺点
2008-06-25 21:08 17289有人说,robbin你说了那么多RoR的优点,你啥时候说说Ro ... -
Skynet --- ruby的类Google Map/Reduce框架
2008-06-02 00:39 8235Skynet是一个很响亮的名 ... -
rmmseg-cpp - 简洁高效的ruby中文分词程序
2008-05-27 00:47 11152我在前一篇文章向大家 ... -
使用libmmseg实现Ruby的中文分词功能
2008-05-24 21:43 11234用Ruby on Rails开发web2.0网站的人都知道,r ... -
mod_rails尝鲜
2008-04-13 14:32 8031Passenger(俗称mod_rails)是 ... -
Lighttpd和RoR安装配置的疑难解答
2008-03-07 11:09 14731之前写过一篇在Linux平 ... -
JavaEye网站的RoR性能优化经验谈
2008-01-20 16:11 18324JavaEye网站从2006年9月11 ... -
RoR部署方案深度剖析
2008-01-14 03:10 14679RoR的部署方案可谓五花八门,有Apache/Fastcgi方 ... -
RoR网站如何利用lighttpd的X-sendfile功能提升文件下载性能
2008-01-12 17:45 10156传统的Web服务器在处理文件下载的时候,总是先读入文件内容到应 ... -
Ruby为什么会受程序员的欢迎?
2008-01-07 20:08 15693孟岩最近写了一篇博客 ... -
Ruby on Rails 2.0的新特性介绍
2007-12-10 21:32 15541万众瞩目的Ruby on Rails 2.0已经发布了,Rai ...
相关推荐
NULL 博文链接:https://qianjigui.iteye.com/blog/2008500
RubyVM-Ruby虚拟机乐高玩具套装
ruby-build - 编译和安装Ruby
ruby代码ruby代码ruby代码ruby代码ruby代码ruby代码ruby代码ruby代码
ruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ruby DBIruby DBI ruby DBI ...
通过USDT导出Ruby VM(MRI)堆栈和对象分配计数跟踪,以进行tracecap提取。 分析代码的设计和实现很大程度上受启发。 安装 将此行添加到您的应用程序的Gemfile中: gem 'tracecap_profiler' 然后执行: $ bundle...
Ruby Hacking Guide是一本探讨C Ruby实现的书,这次发布的部分包括对全书的介绍和本书的第一部分。第一部分的内容包括对Ruby语言一个概要介绍和对Ruby对象模型的讲解。从我个人阅读的感觉来看,第一章对于Ruby语言的...
ruby2ruby 提供一些用来根据 RubyParser 兼容的 Sexps 轻松生成纯 Ruby 代码的方法。可在 Ruby 中轻松实现动态语言处理。 标签:ruby2ruby
《Ruby完全自学手册》是一本完全覆盖Ruby和Ruby on Rails的完全自学手册。《Ruby完全自学手册》的特色是由浅入深、循序渐进,注重理论和实践的结合。虽然定位为入门手册,但是依然涉及许多高级技术和应用,覆盖到的...
在对Ruby进行了简要的综述之后,本书详细介绍了以下内容:Ruby的句法和语法结构,数据结构和对象,表达式和操作符,语句和控制结构,方法、proc、lambda和闭包,反射和元编程,Ruby平台。 本书还包含对Ruby平台上...
Ruby编程,Ruby编程,Ruby编程,Ruby编程,Ruby编程,
ruby源代码 ruby源代码 ruby源代码 ruby源代码2
ruby源代码 ruby源代码 ruby源代码 ruby源代码4
ruby对excel的操作 详细描述ruby对excel的操作
ruby笔记1ruby笔记1ruby笔记1ruby笔记1ruby笔记1ruby笔记1
ruby源代码 ruby源代码 ruby源代码 ruby源代码3
ruby on rails对mongodb的操作ruby on rails对mongodb的操作ruby on rails对mongodb的操作ruby on rails对mongodb的操作
ruby打包文件ruby打包文件ruby打包文件ruby打包文件ruby打包文件ruby打包文件ruby打包文件ruby打包文件ruby打包文件
第二部分:介绍基础语法规则,以及类、模块等面向对象程序设计的思考方法与用词。 第三部分:对一些基础类逐一介绍其功能与用法。 第四部分:介绍一些比较高级的功能,比如Ruby的环境参数、环境变量、迭代器...
ruby interpreter 原理探討 At first glance, learning how to use Ruby can seem fairly simple. Developers around the world find Ruby’s syntax to be graceful and straightforward. You can express ...