Еда памяти единорога - PullRequest
9 голосов
/ 29 ноября 2011

У меня есть экземпляр m1.small в Амазонке с 8 ГБ на жестком диске, на котором работает мое приложение rails. Он работает ровно в течение 2 недель и после этого вылетает, говоря, что память заполнена. Приложение работает на рельсах 3.1.1, единорог и nginx

Я просто не понимаю, что принимает 13G?
Я убил единорога, и команда 'free' показывает свободное место, в то время как df все еще говорит 100%
Я перезагрузил экземпляр, и все стало работать нормально.

бесплатно (до убийства единорога)

             total       used       free     shared    buffers     cached  
Mem:       1705192    1671580      33612          0     321816     405288  
-/+ buffers/cache:     944476     760716   
Swap:       917500      50812     866688 

df -l (до убийства единорога)

Filesystem           1K-blocks      Used Available Use% Mounted on  
/dev/xvda1             8256952   7837520         4 100% /  
none                    847464       120    847344   1% /dev  
none                    852596         0    852596   0% /dev/shm  
none                    852596        56    852540   1% /var/run  
none                    852596         0    852596   0% /var/lock  
/dev/xvda2           153899044    192068 145889352   1% /mnt  
/dev/xvdf             51606140  10276704  38707996  21% /data  

sudo du -hc --max-глубина = 1 (до убийства единорога)

28K ./root  
6.6M    ./etc  
4.0K    ./opt  
9.7G    ./data  
1.7G    ./usr  
4.0K    ./media  
du: cannot access `./proc/27220/task/27220/fd/4': No such file or directory  
du: cannot access `./proc/27220/task/27220/fdinfo/4': No such file or directory  
du: cannot access `./proc/27220/fd/4': No such file or directory  
du: cannot access `./proc/27220/fdinfo/4': No such file or directory  
0   ./proc  
14M ./boot  
120K    ./dev  
1.1G    ./home  
66M ./lib  
4.0K    ./selinux  
6.5M    ./sbin  
6.5M    ./bin  
4.0K    ./srv  
148K    ./tmp  
16K ./lost+found  
20K ./mnt  
0   ./sys  
253M    ./var  
13G .  
13G total   

бесплатно (после убийства единорога)

             total       used       free     shared    buffers     cached    
Mem:       1705192     985876     **719316**          0     365536     228576    
-/+ buffers/cache:     391764    1313428    
Swap:       917500      46176     871324  

df -l (после убийства единорога)

Filesystem           1K-blocks      Used Available Use% Mounted on  
/dev/xvda1             8256952   7837516         8 100% /  
none                    847464       120    847344   1% /dev  
none                    852596         0    852596   0% /dev/shm  
none                    852596        56    852540   1% /var/run  
none                    852596         0    852596   0% /var/lock  
/dev/xvda2           153899044    192068 145889352   1% /mnt  
/dev/xvdf             51606140  10276704  38707996  21% /data  

unicorn.rb

rails_env = 'production'  

working_directory "/home/user/app_name"  
worker_processes 5  
preload_app true  
timeout 60  

rails_root = "/home/user/app_name"  
listen "#{rails_root}/tmp/sockets/unicorn.sock", :backlog => 2048  
# listen 3000, :tcp_nopush => false  

pid "#{rails_root}/tmp/pids/unicorn.pid"  
stderr_path "#{rails_root}/log/unicorn/unicorn.err.log"  
stdout_path "#{rails_root}/log/unicorn/unicorn.out.log"  

GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)  

before_fork do |server, worker|  
  ActiveRecord::Base.connection.disconnect!  

  ##  
  # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and  
  # immediately start loading up a new version of itself (loaded with a new  
  # version of our app). When this new Unicorn is completely loaded  
  # it will begin spawning workers. The first worker spawned will check to  
  # see if an .oldbin pidfile exists. If so, this means we've just booted up  
  # a new Unicorn and need to tell the old one that it can now die. To do so  
  # we send it a QUIT.  
  #  
  # Using this method we get 0 downtime deploys.  

  old_pid = "#{rails_root}/tmp/pids/unicorn.pid.oldbin"  
  if File.exists?(old_pid) && server.pid != old_pid  
    begin  
      Process.kill("QUIT", File.read(old_pid).to_i)  
    rescue Errno::ENOENT, Errno::ESRCH  
      # someone else did our job for us  
    end  
  end  
end  


after_fork do |server, worker|  
  ActiveRecord::Base.establish_connection  
  worker.user('rails', 'rails') if Process.euid == 0 && rails_env == 'production'  
end  

Ответы [ 5 ]

15 голосов
/ 18 ноября 2012

Я только что выпустил камень ' Единорог-работник-убийца '. Это позволяет вам уничтожать работника Unicorn на основании 1) максимального количества запросов и 2) размера памяти процесса (RSS), не влияя на запрос.

Это действительно удобно. Внешний инструмент не требуется. Сначала добавьте эту строку в ваш Gemfile.

gem 'unicorn-worker-killer'

Затем, пожалуйста, добавьте следующие строки в ваш config.ru.

# Unicorn self-process killer
require 'unicorn/worker_killer'

# Max requests per worker
use Unicorn::WorkerKiller::MaxRequests, 10240 + Random.rand(10240)

# Max memory size (RSS) per worker
use Unicorn::WorkerKiller::Oom, (96 + Random.rand(32)) * 1024**2

Настоятельно рекомендуется рандомизировать пороговое значение, чтобы не убивать сразу всех работников.

9 голосов
/ 30 ноября 2011

Я думаю, вы совмещаете использование памяти и использование дискового пространства.Похоже, что Unicorn и его потомки использовали около 500 МБ памяти, вы посмотрите на второе число «- / + buffers / cache:», чтобы увидеть реальную свободную память.Что касается дискового пространства, моя ставка идет на какой-то лог-файл или что-то в этом роде.Вы должны сделать du -h в каталоге данных, чтобы выяснить, что именно использует столько памяти.И последнее, малоизвестный факт, что Ruby никогда не возвращает память обратно в ОС, если она выделяет ее.Он по-прежнему использует его для внутреннего использования, но как только Ruby забирает часть памяти, единственный способ вернуть ее неиспользуемой памяти обратно в ОС - это выйти из процесса.Например, если у вас есть процесс, который увеличивает объем используемой памяти до 500 МБ, вы не сможете снова использовать эти 500 МБ, даже после того, как запрос завершен и цикл GC запущен.Тем не менее, Ruby будет повторно использовать эту выделенную память для будущих запросов, поэтому вряд ли она будет расти дальше.

Наконец, Сергей упоминает, что Бог контролирует память процесса.Если вы заинтересованы в использовании этого, здесь уже есть хороший файл конфигурации здесь .Обязательно прочитайте связанную статью , поскольку в конфигурационном файле единорога есть ключевые вещи, которые, как предполагает этот конфиг бога, у вас есть.

3 голосов
/ 07 декабря 2011

Как сказал Престон, у вас нет проблем с памятью (более 40% свободного места), у вас проблема с переполнением диска.du сообщает, что большая часть памяти используется в /root/data.

. Вы можете использовать find для идентификации очень больших файлов, например, ниже будут показаны все файлы в этом каталоге размером более 100 МБ.

sudo find /root/data -size +100M

Если Unicorn все еще работает, lsof (LiSt Open Files) может показать, какие файлы используются вашими запущенными программами или определенным набором процессов (-p PID), например:

sudo lsof | awk  '$5 ~/REG/ && $7 > 100000000 { print }'

покажет вам открытые файлы размером более 100 МБ

2 голосов
/ 29 ноября 2011

Вы можете настроить бог , чтобы наблюдать за вашими работниками-единорогами и убивать их, если они съедают слишком много памяти.Мастер-процесс Unicorn затем раскошелится на другого работника, чтобы заменить его.Проблема решена.: -)

0 голосов
/ 09 ноября 2013

Попробуйте удалить newrelic для вашего приложения, если вы используете newrelic. Newrelic rpm самоцвет утечка памяти. У меня была та же самая проблема, и я почти 10 дней почесал голову, чтобы выяснить проблему.

Надеюсь, это поможет вам.

Я обращаюсь в службу поддержки newrelic, ниже приводится их ответ.

Спасибо за обращение в службу поддержки. Я глубоко сожалею о расстраивающем опыт у вас был. В качестве инструмента мониторинга производительности наши намерение «сначала не навреди», и мы очень серьезно.

Мы недавно определили причину этой проблемы и выпустили патч, чтобы решить это. (см. https://newrelic.com/docs/releases/ruby). Мы надеюсь, что вы решите возобновить мониторинг с помощью New Relic с этим исправлением. Если вы заинтересованы в этом, убедитесь, что вы используете по крайней мере v3.6.8.168 отныне.

Пожалуйста, дайте нам знать, если у вас есть дополнительные вопросы или проблемы. Мы с нетерпением ждем их решения.

Даже если я попытался обновить newrelic gem, но он все еще терял память. Наконец, я должен удалить rewrelic, хотя это отличный инструмент, но мы не можем использовать его за такую ​​цену (утечка памяти).

Надеюсь, что это поможет вам.

...