Подтвердить что ты не робот

Выполнение Ruby GC превышает ~ 250-320 мс за запрос

У меня есть приложение ruby ​​on rails. Я изучаю снижение Apdex в моем портале NewRelic, и я вижу, что в среднем на время выполнения GC тратится 250-320 мс времени. Это очень тревожное число. Я включил снимок экрана ниже.

Моя версия Ruby:

ruby ​​1.9.3p194 (исправление 2012-04-20 35410) [x86_64-linux]

Любые предложения по настройке этого были бы идеальными. Это число должно быть значительно ниже.

enter image description here

4b9b3361

Ответ 1

Вы проводите столько времени в GC, потому что часто работаете с GC. Ruby, по умолчанию, устанавливает параметры GC, которые подходят для небольших скриптов, а не для больших приложений. Попробуйте запустить приложение со следующими параметрами среды:

RUBY_HEAP_MIN_SLOTS=800000
RUBY_FREE_MIN=100000
RUBY_GC_MALLOC_LIMIT=79000000

Что это будет делать, это увеличить начальный размер распределения кучи и заполнить номера GC, чтобы он не выполнялся довольно часто. Это может позволить вашему приложению использовать немного больше оперативной памяти, но это должно значительно сократить время, затрачиваемое на GC. В настройках по умолчанию вы, вероятно, используете GC несколько раз за запрос; вы хотите, чтобы в идеале он выполнял его каждые несколько запросов (или даже лучше, между запросами с чем-то вроде Unicorn OOB:: GC).

Это мои настройки GC для моего приложения, и вы захотите настроить их вверх и вниз, как это наиболее подходит для вашего приложения, чтобы найти правильные настройки; вы стреляете в середину, где вы не запускаете GC так часто и не имеете чрезмерного использования памяти. Это специфично для каждого приложения, хотя, поэтому нет рекомендаций по шаблонам, которые я могу дать, какие именно эти настройки должны быть. Увеличение от значений по умолчанию (слоты 10k, фактор роста 1.8x) должно иметь непосредственное влияние, и вы можете настраивать вверх и вниз оттуда, как лучше всего подходит для вашего текущего ситутирования.

Здесь полная запись этих параметров здесь и более подробная информация здесь, и хотя эти сообщения были написаны для REE 1.8.7, они применимы и к Ruby 1.9.2+.

Это некоторые довольно экстремальные числа, поэтому возможно, что вы делаете что-то в своем приложении, что заставляет вас выделять гораздо больше ОЗУ, чем вам, поэтому я бы посоветовал вам быть подозрительным и расчесывать ваше приложение, выглядящее за чрезмерные ассигнования. Однако переменные окружения GC должны помогать сортировать ситуацию в любом случае.

Ответ 2

Вы должны использовать трассировку выделения, чтобы узнать, где ваш код выделяет объекты, и сколько. Я использовал memprof в прошлом с отличными результатами... Большой недостаток заключается в том, что он работает только под Ruby 1.8 (надеюсь, ваш код совместим с 1.8.7).

Если вы можете запустить приложение под Ruby 1.8.7, установите "memprof" gem и:

require 'memprof'
GC.disable
Memprof.track { run_test_code_here }

Это напечатает список выделенных объектов (сгруппированных как по классам, так и по исходной строке, где произошло выделение) на стандартный вывод.

Когда у вас возникают проблемы с чрезмерным временем, затрачиваемым на сборщик мусора, обычно трассировка выделения показывает одно или два места, где ваша программа выделяет тонны объектов. Невозможно заранее сказать, каким будет решение, но часто оно будет включать либо:

  • чтобы избежать повторных вычислений,
  • с использованием деструктивных операций, где это безопасно (например, map! вместо map),
  • повторное использование временного объекта в цикле (сброс его состояния каждый раз), а не выделение нового на каждой итерации или
  • избегая использования строковых констант (или массива/хэш-литералов) в цикле, который выполняется много раз (на каждой итерации будет выделен новый объект).

Ответ 3

Там также этот маленький взлом, который может работать. Но большие приложения, как правило, выделяют такой большой объем памяти, что вы убиваете работника за запрос: -/

Ответ 4

Предполагая, что вы не создаете ненужные объекты по ошибке, я слышал, что один хак/решение (помимо использования JRuby) - это принудительное включение GC после завершения отправки ответа. Таким образом, у вас большая пауза, но потребитель не видит ее. Если у вас так много мусора, вы видите несколько пауз, подобных этому, тогда вам может быть не повезло.

Этот трюк может работать или не работать для ваших нужд.

-JRuby парень, который беседует с людьми с проблемами МРТ:)