Отладка утечки памяти в sidekiq с помощью jemalloc
Итак, у меня утечка памяти в моем рабочем в Sidekiq. У меня есть рабочий сервер с одной очередью только для этой рабочей задачи, которая получает около 10 ГБ RSS в неделю.
Я попытался воспроизвести его локально, используя только 1 рабочий поток и вуаля - я получаю от 200M до 1G за одну ночь, обрабатывая 1 задание в минуту. Естественно, я хочу знать, что происходит, поэтому я также веду журнал RSS, heap_live_slots и heap_free_slots. Когда я отображаю результаты, я вижу устойчивый рост RSS, в то время как живые и свободные слоты колеблются случайно, но в четко определенных и постоянных границах, в то время как их сумма остается постоянной.
На этом этапе я прихожу к выводу, что утечка, вероятно, происходит не в коде Ruby, а скорее в каком-то родном расширении. Поэтому я переустанавливаю ruby с поддержкой Jemalloc через RVM:rvm reinstall 2.4.2 --with-jemalloc
Затем я настроил MALLOC_CONF
:
export
MALLOC_CONF='prof_leak:true,lg_prof_sample:0,prof_final:true,stats_print:true'
И запустить Sidekiq. Недавно запущенный Sidekiq с 1 рабочим потоком стоит около 200M RSS, но когда я нажимаю Ctrl+C и смотрю статистические данные jemalloc, я вижу нечто совершенно иное:
Arenas: 32
Quantum size: 16
Page size: 4096
Maximum thread-cached size class: 32768
Allocated: 34056, active: 61440, metadata: 2949272, resident: 2981888, mapped: 6352896, retained: 2035712
Какие? 6М сопоставлены? Это не может быть правдой. Поэтому я запускаю irb и делаю следующее:
2.4.2 :001 > arr = []
=> []
2.4.2 :002 > loop do
2.4.2 :003 > arr << 'a'*10000000
2.4.2 :004?> sleep 1
2.4.2 :005?> end
После ожидания, пока процесс irb не поднимется до 1G RSS, я останавливаю процесс... и вижу точно такие же числа. Может быть, визуализация графика звонков поможет мне понять, что происходит?
jeprof --show_bytes --pdf `which ruby` jeprof.10536.0.f.heap > ruby.pdf
Using local file /home/mhi/.rvm/rubies/ruby-2.4.2/bin/ruby.
Using local file jeprof.10536.0.f.heap.
No nodes to print
Так что что-то явно не так, и вот что мне нужно, чтобы выяснить.
Вот полный вывод статистики jemalloc: https://pastebin.com/RiMLtqA6
UPD.
Итак, я обновил все гемы, связанные с нативным расширением, вот выводbundle exec ruby -e 'puts Gem.loaded_specs.values.select{ |i| !i.extensions.empty? }.map{ |i| "#{i.name} #{i.version}" }'
:
io-console 0.4.6
nokogiri 1.8.1
bcrypt 3.1.11
debug_inspector 0.0.3
binding_of_caller 0.7.2
json 2.1.0
capybara-webkit 1.14.0
damerau-levenshtein 1.3.0
unf_ext 0.0.7.4
eventmachine 1.2.5
ffi 1.9.18
kgio 2.11.0
msgpack 1.1.0
mysql2 0.4.9
rainbow 2.2.2
raindrops 0.18.0
rbtrace 0.4.8
stackprof 0.2.10
therubyracer 0.12.3
unicode 0.4.4.4
unicorn 5.3.0
Тот же результат: RSS, Слоты памяти
1 ответ
В Ruby 2.4.2 есть известная проблема сjemalloc
,
проблема была закрыта около месяца назад, но я не знаю, пропатчен ли используемый вами пакет... На самом деле, я не думаю, что патч был выпущен. Это, вероятно, все jemalloc
данные статистики не имеют значения.
Кроме того, это похоже на вопрос XY (вы спрашиваете о jemalloc
, в то время как вы, вероятно, хотите решение проблемы утечки памяти).
Прежде чем предположить утечку памяти в нативном коде (хотя это явная возможность), я хотел бы рассмотреть, как область действия задачи может повлиять на сборщик мусора, и попытаться минимизировать как область действия, так и любые переменные с длительным сроком службы.
Например, если ваша задача Proc
, это может быть связано с глобальной областью действия, что означает, что некоторые переменные могут жить вечно...
Попробуйте заключить задачу в функцию и убедитесь, что ни одна из переменных не указана после выполнения задачи.