新手问题 Ruby 进程占用内存越来越大

jasonshl · 2015年09月07日 · 最后由 jasonshl 回复于 2015年09月14日 · 5850 次阅读

最近发现服务器上的 8G 内存几乎被用尽,newrelic 显示 ruby 进程一共用了 4.58 个 G

某一个使用率比较高的进程占了 2 个多 G:

本地测试的时候发现每次刷新页面获取数据的时候(业务是一次性把当前用户有关数据全部获取)也是 ruby 进程占用内存几 M 的增加

是内存泄露吗 还是缓存了数据了?

求大神指点@Rei

环境:ruby on sinatra,nginx + thin

activerecord 惹的祸。。

#1 楼 @pynix 非常感谢回复,新手不是很懂 能否详细点? 数据库是 mongodb,用 mongomapper 定义的 model 类似: class Role include MongoMapper::Document

# 主键 key :_id, ObjectId, :required => true

# 名称 key :name, String, :required => true

# 创建时间 key :created, Time

# 修改时间 key :modified, Time

end

#1 楼 @pynix 你是说从数据库中获取的数据缓存了?

#2 楼 @jasonshl 可以先用 monit 增加一个监控来处理,定期 kill 掉内存过大的进程。不过内存泄露差起来就比较困难了,一种是利用 ObjectSpace 对象。

#3 楼 @jasonshl orm 为了加速查询把查出来的数据都 hold 在内存,不吃内存才怪。

#4 楼 @jimrokliu 目前情况来看 内存占用一直保持 4 个多 G 无宕机 有可能是 orm 的原因,接下来如你所建议的 就要防止内存泄露了 哈哈 多谢

#5 楼 @pynix 现象看来是这样的 多谢多谢

#6 楼 @jasonshl 如果你没用用 memcahed 做缓存的话,可以试试将缓存分离到 memcached 中,当然这个过程不是那么容易。但会保证你 kill 进程后,应用重启后的响应速度不会发生大的变化。

一个进程 2 个 G, 别的都没事,怎么可能是 ActiveRecord 或者 MongoMapper 的原因。再说这么成熟的库,要有这样的 bug, 早就一堆人跳起来了。

认真排查吧,看看这个进程跟别的有什么区别,然后再排除、假设、试验。

这进程居然不挂了。。。。要是挂了可能好排查一些。。

@pynix 要挂了才知道原因就没法做优化了。

我之前做过类似的排查,也是内存占用稳定攀升。我的做法是,开一个临时 branch, controller action 结束时查询内存占用(可以调用 shell script),加入 response(用了一个临时的 header)。

然后做一个 rake task,循环调用该 API, 打印内存占用结果。成功重现内存稳定攀升的 pattern 之后就是一个很好的开端了。

后来一步步排查,遇到可疑的代码就替换或暂时去掉。最后的结果是render file: ..有问题,内存不能去掉。其他团队定期在这里拿准备好的 JSON 文件,之前很小的文件不觉得,后来文件越来越大,造成内存攀升明显。摸索着改为 send_file 后一切正常,再大的文件都不是问题了。

直接用上 rack-mini_profiler 帮你查询每个请求中内存的使用量,还有 ruby 的很多默认库比如 net/http 有不释放文件缓存的问题。

#1 楼 @pynix 你这是从哪确定 ActiveRecord 的问题?

楼主把 Gemfile 贴出来看看

#15 楼 @huacnlee 出了问题不要靠猜。。。

#12 楼 @rei 多谢“调试,不要猜”,有结果会发在下面到时再麻烦指点 哈哈

#17 楼 @huacnlee 由于项目不是 rails 框架 没有 gemfile,也是无经验并没有做记录,现在只能提供 gem list: *** LOCAL GEMS ***

activemodel (4.2.3, 4.1.4) activesupport (4.2.3, 4.1.4) addressable (2.3.8, 2.3.6) autoparse (0.3.3) aws-sdk (1.46.0) aws-sdk-core (2.1.13) aws-sdk-resources (2.1.13) backports (3.6.6, 3.6.0) bigdecimal (1.2.7, 1.1.0) bson (1.10.2) bson_ext (1.10.2) builder (3.2.2) bundler (1.10.6, 1.6.2) bundler-unload (1.0.2) daemons (1.2.3, 1.1.9) eventmachine (1.0.8, 1.0.3) executable-hooks (1.3.2) extlib (0.9.16) faraday (0.9.1, 0.9.0) gearman-ruby (4.0.5, 3.0.7) gem-wrappers (1.2.7, 1.2.4) google-api-client (0.8.6, 0.7.1) googleauth (0.4.2) i18n (0.7.0, 0.6.9) io-console (0.4.2, 0.3) jmespath (1.0.2) json (1.8.3, 1.8.1, 1.5.5) jwt (1.5.1, 1.0.0) launchy (2.4.3, 2.4.2) little-plugger (1.1.3) logging (2.0.0) mailfactory (1.4.0) memoist (0.12.0) mime-types (2.6.1, 2.3) mini_portile (0.6.2, 0.6.0) minitest (5.8.0, 5.3.5, 2.5.1) mongo (1.10.2) mongo_mapper (0.13.1, 0.13.0) multi_json (1.11.2, 1.10.1) multipart-post (2.0.0) nokogiri (1.6.6.2, 1.6.3.rc3) plucky (0.6.6) r18n-core (1.1.11) rack (1.6.4, 1.5.2) rack-protection (1.5.3) rack-test (0.6.3, 0.6.2) rake (10.4.2, 0.9.2.2) rdoc (4.2.0, 3.9.5) retriable (2.0.2, 1.4.1) rubygems-bundler (1.4.4) rufus-scheduler (3.1.3, 3.0.8) rvm (1.11.3.9) signet (0.6.1, 0.5.1) sinatra (1.4.5) sinatra-contrib (1.4.6, 1.4.2) sinatra-r18n (1.1.11) thin (1.6.2) thor (0.19.1) thread_safe (0.3.5, 0.3.4) tilt (2.0.1, 1.4.1) tzinfo (1.2.2, 1.2.1) uuidtools (2.1.5, 2.1.4) 这是服务器上的,ruby 版本 ruby 1.9.3p547,不久前被别人 gem update 了 所以更新了很多包 这也是纠结的地方。

由于现在未有宕机现象,可能未引起老板重视 故只能业余时间搞,回复慢 请各位见谅啊 PS:ruby 占用内存一直稳定在 4 个多 G

几个建议:

  1. 用 Ruby 2.2
  2. 换 Unicorn 或 Puma,能启用 Copy on Write 功能,有效节约内存;
  3. 请楼主再详细介绍项目的情况,什么功能,日流量多少,流量大的时什么功能,那些功能做了什么事情;
  4. bson 现在的最新版本和你安装的已经差很远了,如果你有在用 MongoDB 的话建议更新,可以不需要 bson_ext 了;

............ 你发你系统的 Gem 我无法看出问题,没有 Gemfile,你居然没用 Bundler ... 请用上,固定好适合项目的 Gem 版本,尝试跑一天看看

MongoMapper 在用么?这货已经一年没更新了,如果可以,建议换成 Mongoid


上面只是一些建议,和你的 Memory leak 无关,你需要告诉我详细情况,最好是能看到代码,才能发现问题。

#22 楼 @huacnlee 源码已发 gmail,由于是新手 第一个项目 不足请指正

@jasonshl 为了便于后面其他人参考,这里回复问题

  1. app.rb#18 存在明显泄露迹象
$connections = []

before do
  $connections << request
end

after do
  $connections.delete(request)
end

你确定任何时候 request 都能清掉?如果不能这里就是泄露的最大隐患


顺便说一句,如果技术能力不够,请用 Rails,不要用 Sinatra 之类的简单框架,你们项目的问题不是一点点。

#24 楼 @huacnlee $connectinos 有一个接口 (在 export.rb 里) 获取它的 也是为了观察刚加的 不是一直都有,我去掉

你还没有告诉我那个路径访问量最高

#26 楼 @huacnlee '/uf/startup' 初始化接口和 '/uf/changeset' 获取一段时间发生变化的数据接口,具体还没有统计过。。看 log 里这两个挺多

export.rb 里面那么多类变量是为何?为何不用实例变量?

@@form_name = form.name
@@fields = form.current.fields
@@table_fields = Array.new

#28 楼 @huacnlee 为了.erb 文件能访问到这些变量,不过貌似 erb 可以传参数 这样确实不好。已记下,多谢

#29 楼 @jasonshl 一个 @ 就可以了吧

#30 楼 @huacnlee 是的 哈哈,ps:看了 ruby-china 的代码中才知道 原来包可以从 ruby.taobao.org 获取。。节省大把时间哈 ~!~,又 ps:这两天在偷偷的搞升级 ruby O(∩_∩)O 哈哈~

ruby 从 1.9.3 无痛升级到 2.2.1,后面继续观察

#32 楼 @jasonshl 可以尝试下我以前尝试过的一些方法~ https://ruby-china.org/topics/27057

#33 楼 @jackxu 正拜读,多谢!

需要 登录 后方可回复, 如果你还没有账号请 注册新账号