Rails 检测 Rails action 的内存开销

zhenjunluo · 2013年10月08日 · 最后由 Q1042883322 回复于 2020年08月10日 · 5008 次阅读

最近一个 rails app 内存老是报警,观察发现 ruby 进程消耗的内存会成倍的增长,从原来的 200 多兆,增长到四五百兆,然后是七八百兆,最多的时候是 1G 以上,用的是 unicorn,6 个 ruby 进程,请求多的话,会有四五个进程同时消耗内存都快 1G 了,搞得服务器经常报警,负载很高,而且 ruby 进程的内存只会增加,不会减少。

怎么样才能快速的找出,是哪里出了问题,那里的代码消耗内存最多?

下面是解决方法:

  1. 在日志中记录下来每个 action 的内存消耗
  2. 记录最费内存的 actions
  3. 找出 action 中是那部分的代码有问题
top -p $(pgrep -d',' ruby)  #实时观察每个ruby进程的内存开销
#application.rb

around_filter :log_rss      #具有before_filter和after_filter的功能

def log_rss
    before_rss,before_rss_t = _worker_rss    #action前该进程的内存
    yield                                                     #执行action
    after_rss,after_rss_t = _worker_rss        #action后该进程的内存
    after_rss_t ||= 0
    before_rss_t ||= 0
    if after_rss_t - before_rss_t > 100000000  #大于100M(大概)
      logger.info "#{controller_name}_#{action_name} rss info #{Process.pid} VmRSS: #{before_rss}----#{after_rss}"
    end
  end

def _worker_rss
    proc_status = "/proc/#{Process.pid}/status"
    if File.exists? proc_status
      open(proc_status).each_line { |l|
        if l.include? 'VmRSS'
          ls = l.split
          if ls.length == 3
            value = ls[1].to_i
            unit = ls[2]
            val = case unit.downcase
                  when 'kb'
                    value*(1024**1)
                  when 'mb'
                     value*(1024**2)
                  when 'gb'
                     value*(1024**3)
                  end
            return ["#{value} #{unit}",val]
          end
        end
      }
      ["0",0]
    end
    ["0",0]
  end

这样就可以找到哪些 action 是有问题的了,接下来就要查找 action 中是那部分代码写的有问题了,原理还是同 log_rss 一样,先记录可以代码执行前的 rss,在记录可以代码执行后的 rss,两者对比,找到最费内存的代码!

这样也行,牛。!

new relic 更方便直接點。不過樓主也太有心思了

#2 楼 @chenillen 我用过 new relic 的试用版,感觉给出的信息太多太细了,看着很有压力,而且这个是国外的,不知道会不会被墙,网络稳定性好不好,能否分享下心得?

#3 楼 @zhenjunluo 自己有個應用一直用,網絡穩定性現在沒有問題,new relic 用 SSL,即使是免費版本也沒問題。目前我覺得被牆的機率比較小,因為只要你不用他的前段監控,類似 GA 那種,後端應用非常迅速,出現問題也是及時報錯。

同時也用他監控服務器。

这招对于线程模型就比较尴尬了。

#5 楼 @iBachue 现在一直用的是 rails3,还没接触到多线程,如果是多线程环境,有什么好的思路吗?

#8 楼 @hooopo 有个疑问,get_current_memory 都是整个进程的内存,并没有计算出来进程中单独的一个线程的内存消耗

@huacnlee,发现 rubychina 最近有个问题,发帖和提交回复点击一次没反应,有些时候要点击好几次

#10 楼 @zhenjunluo 不会吧,一直感觉很正常

#10 楼 @zhenjunluo 是的,我最近几天也遇到了

#10 楼 @zhenjunluo #11 楼 @huacnlee 我的确有这个问题,提交一次没反应,第二次提交提示说已经提交了之类的信息

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