Утечка памяти на сервере 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.