У меня есть задание на экспорт, которое экспортирует большой объем данных из нашей MySQL БД. По мере роста данных я заметил, что для этого задания sidekiq требуется слишком много памяти. На сервере 32 ГБ, а после экспорта требуется 28 ГБ. Когда я останавливаю процесс sidekiq, использование памяти падает до 8 ГБ.
Я уже следовал руководству здесь https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting
- предотвращение фрагментации памяти с помощью
MALLOC_ARENA_MAX=2
- очистить кеш запросов
ActiveRecord::Base.connection.clear_query_cache
Я нахожусь на Ruby 2.6.5p114 и попытался изолировать проблему, создав новое приложение rails в производстве и используя мою БД в качестве бэкэнда:
gem install rails --version 5.2.4.3
rails new debug -d mysql
Я создал пустую модель, чтобы избежать пользовательских методов в моем коде, которые могут вызвать проблему:
class Variant < ApplicationRecord
end
Этот сценарий просто загружает 1 миллион объектов из БД и печатает использование памяти:
# memory.rb
def memory
(`ps -o rss= -p #{Process.pid}`.to_i.to_f / 1024).to_s + " MB"
end
def load_variants
puts "load_variants..."
Variant.uncached do
variants = Variant.limit(1_000_000).to_a
puts "variant.count: #{variants.count}"
end
end
puts memory
load_variants
puts memory
puts "GC.start..."
GC.start
puts memory
# second run
load_variants
puts memory
puts "GC.start..."
GC.start
puts memory
Это результат:
root@6e79d7a97d9c:/usr/src/debug# rails r memory.rb
76.93359375 MB
load_variants...
variant.count: 1000000
2436.3125 MB
GC.start...
2421.046875 MB
load_variants...
variant.count: 1000000
2436.3828125 MB
GC.start...
2436.3984375 MB
- он начинается с
76.93359375 MB
- после загрузки 1 млн объектов память увеличивается до
2436.3125 MB
- сборка мусора уменьшает память до
2421.046875 MB
, , но я ожидал бы значительно большего падения! - интересно , второй прогон только увеличивает память до
2436.3828125 MB
- последний
GC.start
как-то увеличивает памяти немного до 2436.3984375 MB
Итак, я хотел бы знать, как это могло быть? В ActiveRecord должно быть что-то, о чем я не знаю, и я хотел бы понять, как все это работает и почему память не освобождается.
После этого logi c объем памяти должен увеличиться на каждый запрос, который читает данные, но я предполагаю, что есть что-то другое при использовании в цикле запрос-ответ.