2017-04-21 1 views
1

Google은 Heroku (RAM - 512mb)에 배포 된 레일 앱을 보유하고 있습니다. 13k + 객체를 반환하는 API (성장 중)가 있습니다. Heroku 앱의 메모리는 RAM의 200 %를 차지합니다. 내 애플 리케이션을 다시 시작 하고이 특정 API를 칠 3-4 번, 메모리가 RAM 크기를 즉시 교차하는 경우. 메모리 누수가 있습니까? 메모리에 너무 많은 응답 시간이 소요됩니까?메모리가 생산중인 레일 앱에서 초과 함 (Heroku에 배포 됨)

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

모델 코드 나 프로덕션 데이터베이스를 덤프 및 derailed_benchmarks 보석으로 로컬로 실행

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] 

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 코드입니다. 런타임시 메모리 크기를 얻으려면이 기능을 사용했습니다.

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

는 여기에 메모리 크기를보고 정상을 사용하고 50 시간 로컬 API를 명중

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 stats

저는 개발과 생산에 새로운 유물을 사용하고 있습니다. 응답 시간의 대부분은 컨트롤러 방법에 의해 소비된다는 것을 보여줍니다.

+1

왜 한 번에 13k 개 요소를 모두 반환해야합니까? 이것은 확장되지 않습니다. 왜 각 요청에 대해 각 요소에 대해'coun','date'와'rel_id'를 재 계산해야합니까?이 값을 데이터베이스에 저장하거나 적어도 데이터베이스에서 계산할 수 있습니까? – spickermann

답변

0

로컬에서 GC을 사용하지 않도록 설정하면 너무 많은 메모리를 차지하고있는 정보를 찾아서 최적화하려고 할 수 있습니다.

  • 당신이 올바른 관계를 포함한 : 여기

    그러나

    몇 가지 시도인가? 분명히 user: :opponent 만 입력하면됩니다.
  • class.class_eval은 (는) 귀하의 each 블록에있는 것이 정말 나쁜 것처럼 보입니다.
1

13k + 항목을 모두 한꺼번에 반환하는 대신 일괄 적으로 반환 할 수 있습니다. 그렇게하면 RAM을 많이 소모하지 않게됩니다. 함수 "find_each"를 사용하여 레코드를 1000 개로 반환하는 것이 좋습니다. this 링크를 확인할 수 있습니다.

1
Model.all 

은 모든 ActiveRecord 개체를 한 번에 수화합니다. 이것은 매우 나쁜 생각입니다. 특히 당신이 eager_loading 인 경우 3 가지 다른 관련 모델이 포함됩니다.

대신 컬렉션을 반복하기 위해 #find_each 메서드를 사용하여 가비지 수집기가 처리 될 때 각 배치에서 사용하는 메모리를 회수 할 수 있도록하는 것이 좋습니다.

또한이 많은 데이터로 단일 응답을 반환하는 것은 좋지 않습니다. 사용자가 점진적으로 데이터를 사용할 기회를 제공하는 페이징 시스템을 API에 구현해야합니다.