生产中的rails应用程序内存超出(在Heroku上部署)

时间:2017-04-21 14:06:14

标签: ruby-on-rails ruby memory heroku ruby-on-rails-5

我们在Heroku上部署了一个rails应用程序(RAM - 512mb)。我们的API返回13k +对象(增长)。 Heroku应用程序的内存超过了RAM的200%。如果我重新启动我的应用程序并点击此特定api 3-4次,内存立即超过RAM大小。是内存泄漏吗?是否有太多的响应时间对内存造成影响?

 Controller code:
 def respond
  @us_anss= UsAns.respond_to_query(params)
 end

型号代码

 def respond_to_query
 anss = self.all.includes(:a, :b, :c)
 anss.each do |ans|
    ans.class.class_eval {attr_accessor :coun, :date, :rec_id}
    ans.coun = ans.user.coun
    ans.date = ans.created_at.to_date
    if ans.rel_id.nil?
      ans.rec_id = nil
    else
      ans.rec_id = ans.user.opponent(ans.rel).id
    end
  end
  return anss
end

rabl代码

Rail code
attributes :ans => :message_content, :user_id => :sen_id
attributes :rec_id, :coun, :date, :latitude, :longitude
collection @us_anss, :object_root => false
child :que do |us_wer|
   attributes :que => :text
   attributes :id, :tri_date
end

的Gemfile

source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
gem 'puma', '~> 3.0'
gem 'rabl'
# Also add either `oj` or `yajl-ruby` as the JSON parser
gem 'oj'
# gem for dashboard
gem 'rails_admin', '~> 1.0'
# Gem for push notifications
gem 'rpush', :git => "git://github.com/moldedbits/rpush.git", :branch => 'master'
# Rack::Cors provides support for Cross-Origin Resource Sharing (CORS) 
 for Rack compatible web applications.
gem 'rack-cors', :require => 'rack/cors'

# Gem for scheduling tasks
gem 'rufus-scheduler'

gem 'jquery-rails', '~> 4.2', '>= 4.2.1'
gem 'bootstrap-sass', '~> 3.3', '>= 3.3.7'
gem 'sass-rails', '~> 5.0', '>= 5.0.6'
gem 'haml', '~> 4.0', '>= 4.0.7'
gem 'newrelic_rpm'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
gem 'geocoder'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
# gem 'rack-cors'

gem 'obscenity', '~> 1.0', '>= 1.0.2'
group :development, :test do
  gem 'dotenv-rails'
  gem 'factory_girl_rails'
  gem 'shoulda-matchers', '~> 3.1', '>= 3.1.1'
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platform: :mri
  gem 'rspec-rails', '~> 3.5'
  gem 'airborne'
  gem 'faker', '~> 1.6', '>= 1.6.6'
  # Use sqlite3 as the database for Active Record
end
gem 'rake', '>=11.3.0'
gem 'scout_apm'
group :development do
  gem 'sqlite3'
  gem 'listen', '~> 3.0.5'
  gem 'letter_opener'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
 end
gem 'exception_notification'
group :production do
  gem 'pg'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

我转储了生产数据库并使用derailed_benchmarks gem在本地运行它。我使用此功能在运行时获取内存大小。

PATH_TO_HIT=/users/new bundle exec derailed exec perf:mem_over_time

以上是上述命令的日志

86.640625
41.62109375
36.15625
86.3671875
73.2265625
72.78515625
93.78515625
163.53515625
192.04296875
168.1953125
221.4609375
281.02734375
92.8046875
315.203125
150.9609375
209.9453125
324.18359375
327.5390625
346.625
346.76953125
353.06640625
355.0
360.96484375
369.99609375
385.41015625
388.75
391.203125
378.58203125
375.23046875
387.6640625
389.33984375
390.8828125
399.21484375
415.59375
415.8359375
419.88671875
435.46484375
437.91796875
430.77734375
417.00390625
425.43359375
425.58984375
430.51171875
425.8671875
430.2578125
431.16796875
390.44140625
358.81640625
393.890625
399.44140625
403.44921875
412.859375
363.3515625
359.390625
379.11328125
398.55859375
400.31640625
406.91015625
423.31640625
420.875
425.875
426.91796875
426.5859375
430.390625
386.78515625
377.77734375
374.86328125
252.625

我使用tops查看内存大小并在本地命中API 50次。这是顶部的日志 Tops stats

我正在使用新的遗物进行开发和生产。它表明响应时间的主要部分是由控制器方法消耗的。

3 个答案:

答案 0 :(得分:1)

不是一次返回所有13k +项目,而是可以批量返回。这样你就不会消耗那么多RAM。我建议你使用函数“find_each”以1000的批量返回记录。您可以查看this链接。

答案 1 :(得分:1)

Model.all

将立即保湿所有ActiveRecord对象。这是一个非常糟糕的主意。特别是如果你正在eager_loading三个其他相关模型与包含。

我建议您使用#find_each方法来迭代集合,允许垃圾收集器在处理时回收每个批处理所消耗的内存。

不推荐使用这么多数据返回单个响应。 应在您的api上实现一个分页系统,使用户有机会逐步使用数据。

答案 2 :(得分:0)

您可以在本地停用GC以查找占用大量内存的内容并尝试对其进行优化。

但这是一些尝试:

  • 你是否包括正确的关系?显然,您只需要包含user: :opponent
  • class.class_eval在您的each区块中显得非常糟糕。