Rails Rails + Puma 部署,内存只增不减,直到内存占满自动重启

xlaok · 2016年09月01日 · 最后由 yakjuly 回复于 2016年09月07日 · 3498 次阅读

虽然有内存消耗到一定程度之后自动重启的工具,但还是治标不治本吧。

因为有一些数据量很大,并且较为复杂的api,只要一访问,内存就上去十几M,而且res end之后,内存压根不施放,直到占满重启

坛子里也搜了很多资料,帮助不大,也排除了有内存泄漏的gem(如果是内存泄漏的话,表现应该是内存增增减减,而不是一路往上只增不减吧?)

问一下有没有人遇到过类似的问题,是如何解决的?

共收到 20 条回复

只增不减就是内存泄露,看看有没有长周期(全局变量,类变量等)对短周期(局部变量等)的引用,

是不是 GC.disable 了?

#2楼 @huacnlee 没有,搜了全部代码没有有关GC的,GC.enable 回报 false

主要泄露部分的代码 @huacnlee 能否帮review下

get 'records' do
  view = View.find(params[:view_id])

  # 省略鉴权部分

  # view.records_list_ids 是一个大数组,直接从 redis 中拿出来的,可能高达2万个字段,paginate_ids代码见下方
  records_ids = paginate_ids(view.records_list_ids)

  records = Record.where(id: { '$in' => records_ids })
  # where in 之后的排序,O(n)算法,应该没问题
  records =  view.sort_records(records)

  present records, with API::Entities::Records
end
def paginate_ids(collection)
  return [] if collection.blank?

  base_record_index = collection.find_index(params[:from])

  if params[:direction] == 'forward'
    res = collection.slice(base_record_index, params[:limit])
  else
    offset = base_record_index - params[:limit]
    res = if offset >= 0
            collection.slice(offset, params[:limit] + 1)
          else
            collection.slice(0, base_record_index + 1)
          end
  end
end

看不出来,这样

嗯,我的也是用rails+puma,我遇到的情况是:之前服务器运行内存是1G的,跑网站(http://sxysxy.org) top命令看内存基本占满。之后升级内存到2G,过段时间再用top看内存占用又几乎满了。 但是短时间看并没有什么问题,连续运行十几天内存都是那种状态,但是网站很好的运行....qwq

如果内存泄漏的不是很厉害(1天几十M 的话) puma_killer

puma_killer +1

#6楼 @sxysxy 你那就一个个人博客,多少点代码啊,有多复杂啊,怎么会弄出泄漏

容我瞎猜一下,把 Entity Gem 去掉试试,直接渲染用 map 迭代渲染 records

passenger 有参数设置内存释放时间,所以查看一下Puma是否也有。

#11楼 @ruby_sky #8楼 @tzwm 想彻底解决问题

#10楼 @MrPasserby 我也这么想 present records, with API::Entities::Records 改成 present [], with API::Entities::Records 内存就增长很慢,而且有回收的迹象,但是也看不出什么,补充一下这块的代码:

module API
  module Entities
    class Records < Base
      expose :comments_count
      expose :followers, using: API::Entities::Users
      expose :cells, unless: :without_cells do |instance, options|
        self.cells(options[:columns] || self.columns)
      end

      def columns
        object.sheet.columns
      end

      def cells(columns)
        {}.tap do |cells_hash|
          raw_cells = object.cells
          columns.each do |column|
            value = raw_cells[column.column_id]

            case column.type
            when 'date'
                value = value.try(:iso8601, 3)
            when 'metadata'
              meta_type = column.config['type']
              value = object.try(meta_type)

              if %w(created_at updated_at).include?(meta_type)
                value = value.try(:iso8601, 3)
              end
            end

            cells_hash[column.column_id] = value
          end
        end
      end
    end
  end
end

#7楼 @jicheng1014 唉,超级厉害,如果一直访问几万条数据的api,分分钟钟跑满了,现在换成4G要稍稍好一些,但是内存还是一直上涨

#5楼 @huacnlee 附一张内存图,突然减少是重启了服务器,后面的突然升高是我使劲在刷api

先用monit顶一阵。开多个puma的进程,定期重启内存超标的进程。ruby这东西的内存经常会产生这种问题。自杀是避免不了的,memcached的缓存要加上。

某些gem有泄露问题,比如验证码之类的。或其他有c扩展的

#12楼 @xlaok 这玩意增加了这么多代码量,都不知道有啥用,给到调用接口的人,还是不知道该咋整,还不如老老实实写一篇文档来的方便。最后的最后,我还是觉得rails方便,奇怪的问题至少不会太多。

看看 API::Entities::Users 里面有没有引用到 API::Entities::Records. 如果这边声明了 expose :followers 那边又声明一个 expose :records, using: API::Entities::Records 是有可能导致内存问题。

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