Память постоянно растет в приложении Rails

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

Screen dump from New Relic, Dyno memory usage

UPDATED: When this screen dump from New Relic was taken. I have scheduled a web dyno restart every hour (one out of two web dynos). Thus, it does not reach the 500Mb-crash level and it actually gets a bit of a sig saw pattern. The problem is not at all resolved by this though, only some of the symptoms. As you can see the morning is not so busy but the afternoon is more busy.

ОБНОВЛЕНО. Когда был снят этот экранный свал (тот, который был ниже) из New Relic. Я каждый час планировал перезапуск веб-диноза (один из двух веб-динамиков). Таким образом, он не достигает уровня 500Mb-crash, и на самом деле он получает немного рисунка пила sig. Проблема вовсе не устранена этим, а лишь некоторыми из симптомов. Как вы можете видеть, утро не так занято, но днем ​​занят. Я сделал загрузку в 11.30 для небольшой детали, она не могла повлиять на проблему, даже если она отображается как таковая в статистике.

Можно также отметить, что это MIN-память продолжает расти, даже если график показывает AVG-память. Даже когда график, по-видимому, временно опускается на графике, минимальная память остается неизменной или увеличивается. МИН-память никогда не уменьшается!

Приложение (без перезагрузки dyno) увеличит объем памяти до тех пор, пока не достигнет максимального уровня в Heroku, и приложение не сработает с истечением срока действия.

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

Выполнено устранение неполадок

а. Я думал, что проблема будет заключаться в before_filter в application_controller (Переменные переменных в контроллере приложения вызывают утечку памяти в Rails?), но это не проблема.

В. Я установил oink, но он не дает никаких результатов (вообще). Он создает oink.log, но не дает никаких результатов, когда я запускаю "heroku run oink -m log/oink.log", независимо от того, какой порог.

С. Я попробовал bleak_house, но он устарел и не мог быть установлен

Д. Я googled и прочитал большинство статей в теме, но я не мудрее.

Е. Мне бы очень хотелось протестировать memprof, но я не могу его установить (у меня Ruby 1.9x и я не знаю, как понизить его до 1,8x)

Мои вопросы:

Q1. Мне бы очень хотелось узнать имя (имена) переменной (ов), которая увеличивается для каждого запроса, или, по крайней мере, какой контроллер использует большую часть памяти.

Q2. Будет ли контроллер в качестве приведенного ниже кода увеличиваться в памяти?

related_feed_categories = []
@gift.tags.each do |tag|
  tag.category_connections.each do |cc|
    related_feed_categories << cc.category_from_feed
  end
end

(извините, SO не будет переформатировать код, который будет легко читаться по какой-либо причине).

Нужно ли мне "убивать" связанные_feed_categories с "related_feed_categories = nil" или же это делает сборщик мусора?

Q3. Каковы будут мои основные вещи? Прямо сейчас я не могу сузить его ВСЕ. Я не знаю, какая часть кода должна выглядеть глубже, и я действительно не знаю, что искать.

Q4. В случае, если я действительно не смогу решить проблему. Есть ли онлайн-консультационная служба, в которой я могу отправить свой код и получить их, чтобы найти проблему?

Спасибо!

ОБНОВЛЕНО. Получив комментарии, это может быть связано с сеансами. Это часть кода, который, как я думаю, может быть плохим:

# Create sessions for last generation
friend_data_arr = [@generator.age, @generator.price_low, @generator.price_high]
friend_positive_tags_arr = []
friend_negative_tags_arr = []
friend_positive_tags_arr << @positive_tags
friend_negative_tags_arr << @negative_tags    
session["last_generator"] = [friend_data_arr, friend_positive_tags_arr, friend_negative_tags_arr]

# Clean variables
friend_data_arr = nil
friend_positive_tags_arr = nil
friend_negative_tags_arr = nil

он используется в контроллере show # генератора. Когда некоторые подарки были сгенерированы с помощью моего механизма генерации подарка, я сохраняю ввод в сеансе (в случае, если они захотят использовать эту информацию на более позднем этапе). Я никогда не убиваю или не заканчиваю эти сеансы, поэтому, если это может привести к увеличению памяти.

Обновлено: я удалил эту часть кода, но память все еще увеличивается, поэтому я думаю, что эта часть не есть, но аналогичный код может вызвать ошибку?

Ответ 1

Вряд ли наши related_feed_categories спровоцируют это.

Используете ли вы много файлов?

Как долго вы сохраняете данные сеанса? Похоже, у вас есть сайт электронной коммерции, вы держите объекты в сеансах?

В принципе, я думаю, что это файлы или сеанс, или увеличение временных данных, сброшенных при сбое сервера (memcache?).

В середине ночи, я думаю, что у нас меньше клиентов. Можете ли вы опубликовать одну и ту же диаграмму памяти в часы пик?

Это может быть связано с этой проблемой: Память неограниченно растет в пустом приложении Rails

ОБНОВЛЕНИЕ:

Rails не сохраняет все данные на стороне клиента. Я не помню хранилище по умолчанию, bu, если вы не выбрали файл cookie:: store, рельсы отправляют только такие данные, как session_id.

Это несколько рекомендаций по сеансам, ActiveRecord:: SessionStore, по-видимому, лучший выбор для производительности. И вы не должны хранить большие объекты и секреты в сеансах. Подробнее о сессии здесь: http://guides.rubyonrails.org/security.html#what-are-sessions

В части 2.9 у вас есть объяснение, чтобы уничтожить сеансы, не используемые в течение определенного времени.

Вместо хранения объектов в сеансах я предлагаю вам сохранить URL-адрес, предоставляющий результаты поиска. Вы можете даже сохранить его в базе данных, предлагая возможность сохранить несколько исследований для своего клиента и/или по умолчанию загружать последние использованные.

Но на этом этапе мы все еще не полностью уверены, что сессии являются виновниками. Чтобы быть уверенным, вы можете попробовать на тестовом сервере, чтобы стресс протестировать ваше приложение, с истекающими сессиями. Таким образом, вы создаете большое количество сеансов, и, возможно, через 20 минут рельсы должны их подавлять. Если вы обнаружите какую-либо разницу в потреблении памяти, она будет сузить вещи.

Первый случай: при значительном сокращении памяти, когда сеансы заканчиваются, вы знаете, что это связано с сеансом.

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

Третий случай: ничего не меняется (увеличение памяти при обычном), поэтому вы знаете, что это не зависит от количества пользователей. Но я не знаю, что может вызвать это.

Когда я сказал стресс-тесты, я имею в виду значительное количество сеансов, а не стресс-тест. Количество необходимых вам сеансов зависит от вашего среднего числа пользователей. Если у вас было 50 пользователей, до того, как ваше приложение разбилось, 20-30 сеансов могут быть значительными. Поэтому, если у вас их было вручную, настройте более высокий срок действия. Мы просто ищем различия в объёме памяти.

Обновление 2:

Таким образом, это скорее всего утечка памяти. Поэтому используйте пространство объектов, оно имеет метод count_objects, который отобразит все используемые в настоящее время объекты. Он должен сузить вещи. Используйте его, когда память уже много увеличилась.

В противном случае у вас есть bleak_house, камень, способный найти утечки памяти, все еще рубиновые инструменты для утечек памяти не так эффективны, как java, но стоит попробовать.

Github: https://github.com/evan/bleak_house

Обновление 3:

Это может быть объяснение, это не утечка памяти, но она увеличивает память: http://www.tricksonrails.com/2010/06/avoid-memory-leaks-in-ruby-rails-code-and-protect-against-denial-of-service/

Короче говоря, символы сохраняются в памяти до перезапуска ruby. Так что, если символы создаются со случайным именем, память будет расти, пока ваше приложение не выйдет из строя. Это не происходит со строками, это GCed.

Бит старый, но действительный для ruby ​​1.9.x Попробуйте следующее: Symbol.all_symbols.size

Обновление 4:

Итак, ваши символы, вероятно, являются утечкой памяти. Теперь нам еще нужно найти, где это происходит. Используйте Symbol.all_symbols. Он дает вам список. Я думаю, вы можете сохранить это где-нибудь и сделать diff с новым массивом, чтобы увидеть, что было добавлено.

Это может быть i18n, или это может быть что-то другое, генерируемое неявным способом, например i18n. Но в любом случае это, вероятно, генерирует символы со случайными данными в имени. И тогда эти символы больше никогда не будут использоваться.

Ответ 2

Предполагая, что category_from_feed возвращает строку (или, возможно, символ), величина увеличения в 300 МБ весьма маловероятна. Вы можете грубо прийти к этому, профилируя это:

4_000_000.times {related_feed_categories << "Loooooooooooooong string" }

Этот фрагмент будет снимать использование памяти примерно на 110 МБ.

Я бы посмотрел на соединения DB или методы, которые читают файл, а затем не закрывают его. Я вижу, что это связано с фидами, которые, вероятно, означают, что вы можете использовать XML. Это тоже может быть отправной точкой.


Проводя это как ответ, потому что это выглядит плохо в комментариях:/