Утечка памяти на сервере postgresql после обновления до Rails 4

У нас возникает странная проблема с Rails-приложением на Heroku. Juste после миграции из Rails 3.2.17 в Rails 4.0.3 наш сервер postgresql показывает бесконечное увеличение использования памяти, затем он возвращает следующую ошибку для каждого запроса:

ERROR: out of memory
DETAIL: Failed on request of size xxx

Juste после выпуска приложения с рельсами 4, начнет увеличиваться память postgresql.

Как вы можете видеть на скриншоте ниже, он увеличивается с 500 МО до более 3,5 ГБ за 3 часа

enter image description here

Одновременно, совершение в секунду удваивается. Он прошел от 120 фиксаций в секунду:

enter image description here

до 280 фиксаций в секунду:

enter image description here

Стоит отметить, что когда мы перезапускаем приложение, память переходит к нормальному значению 600 Мо до перехода на более чем 3-го часа через несколько часов (тогда каждый запрос sql показывает ошибку "из памяти" ). Это похоже на то, что убийство соединений ActiveRecord освобождает память на сервере postgresql.

У нас может быть какая-то утечка памяти. Однако:

  • Он отлично работал с Rails 3.2. Возможно, эта проблема связана с изменениями, которые мы внесли, чтобы адаптировать наш код к Rails 4 и самому Rails 4.
  • Увеличение количества фиксаций в секунду после восстановления Rails 4 кажется очень странным.

Наш стек:

  • Heroku, x2 dynos
  • Postgresql, Ika plan on heroku
  • Единорог, 3 сотрудника на экземпляр
  • Rails 4.0.3
  • Redis Cache.
  • Примечательные драгоценные камни: отложенные задания (4.0.0), активный админ (на главной ветке), удобный мексиканский диван (1.11.2).

В нашем коде нет ничего необычного.

Наша конфигурация postgresql:

  • work_mem: 100 МБ
  • shared_buffers: 1464MB
  • max_connections: 500
  • maintenance_work_mem: 64MB

Кто-нибудь когда-либо испытывал такое поведение при переключении на Rails 4? Я ищу идею для воспроизведения.

Вся помощь очень приветствуется.

Спасибо заранее.

Ответы

Ответ 1

Я не знаю, что лучше: ответьте на мой вопрос или обновите его... поэтому я решил ответить. Пожалуйста, дайте мне знать, если лучше обновить

Наконец, мы выясним проблему. Начиная с версии 3.1, Rails добавила подготовленные заявления на простой запрос, например User.find(id). Версия 4.0 добавила подготовленные операторы к запросам об ассоциациях (has_many, принадлежит_to, has_one). Например, следующий код:

class User
  has_many :adresses
end
user.addresses

генерировать запрос

SELECT "addresses".* FROM "addresses" WHERE "addresses"."user_id" = $1  [["user_id", 1]]

Проблема в том, что Rails только добавляет подготовленные переменные оператора для внешних ключей (здесь user_id). Если вы используете пользовательский запрос sql, например

user.addresses.where("moved_at < ?", Time.now - 3.month) 

он не добавит переменную в подготовленные операторы для move_at. Таким образом, он генерирует подготовленные заявления каждый раз, когда вызывается запрос. Rails обрабатывает подготовленные операторы с пулом максимального размера 1000.

Однако подготовленные сообщения postgresql не используются совместно, поэтому через один или два часа каждое соединение содержит 1000 подготовленных операторов. Некоторые из них очень большие. Это приводит к очень большому потреблению памяти на сервере postgreqsl.