Место преступления:
Однажды в 20-х годах нашей эры я неторопливо завтракал в компании, и вдруг с моего мобильного телефона пришло оповещение приложения! ! ! Откройте его и посмотрите:Использование устаревшей памяти приложения превышает 95%В поле зрения появилось несколько крупных символов, и я так испугалась, что быстро уронила мясные булочки в руку и быстро проверила!
Следующее изображение является свидетельством преступления, которое было повторно снято из мониторинга приложения после решения проблемы.Очевидно, что старость приложения часто выполняет полную сборку мусора в течение определенного периода времени, а максимальная точка памяти завис на 100%.
Процесс охоты:
Кхм, как зрелый java siege lion, столкнувшись с вором вроде oom, автор естественно сохранял спокойное лицо (вообще-то я сильно паниковал. такой горшок).
В то время первой реакцией было сначала проконсультироваться с коллегами по эксплуатации и обслуживанию и обнаружить, что на платформе мониторинга нет встроенного инструмента анализа памяти, и необходимо выполнить анализ дампа самостоятельно. В данном случае могу только стиснуть зубы.Про подключение к трамплину и вход в продакшен автор ничего не говорит.jpsНайдите идентификатор процесса текущего Java-приложения, еще один трюкjmap -dump:format=b,file=filename pid, я думал, что когда я получу файл дампа, я обязательно исправлю твоего убийцу. Спустя долгое время ~~~ 10 минут я наконец-то получил файл дампа (здесь опущены всякие сообразительности и храбрости с экспортом файлов производственной среды).
Автору не терпится достать левый и правый скальпели (тот, что идет в комплекте с javavisualvmс известным программным обеспечением для внешнего анализаmat), готовый к вскрытию файла дампа. Ведь когда я впервые воспользовался ножом, я полтора раза не умел пользоваться рукоятью, я действительно потерял морду своего осадного льва! После долгого метания я наконец-то открыл мат и загрузил файл дампа. (Mac, использующий мат, может иногда сталкиваться с ямами, которые не запускаются, я не буду здесь вдаваться в подробности, пожалуйста, изучите себя / Google)
Первый нож, вскрывающий труп, обнажает окровавленные внутренние органы, как показано ниже:
Зоркий автор с первого взгляда нашел, у меня такая большая опухоль! ! ! Памяти 1.9G занимает 1.7G.Откуда эта опухоль?Не терпится провести второй нож в место указанное красной стрелкой! Метод ножа заключается в следующем: нажмите на проект Leak Suspects of mat's Reports, мат автоматически обнаружит некоторых виновников, которые подозреваются в том, что они причинили нам ущерб. какие! что мы видим, аlogback.classic.AsyncAppenderОбъект, он занимает 89,74% памяти живой! ! ! Любой, кто имел дело с фреймворком logback, должен знать, что AsyncAppender — это объект-оболочка конфигурации фреймворка logback, который отвечает за упаковку и настройку некоторых конфигураций журнала. Мы не можем не начать подозревать, что причина смерти этого трупа как-то связана с журналом приложений! С подозрением автор глубоко вонзил нож в труп.Потяните, чтобы аккумулировать объекты в элементе дерева dominator, в котором для нас указана структура памяти этого объекта asyncAppender. Как и ожидалось, инфраструктура журналирования будет использовать очередь для кэширования объектов loggingEvent, и каждый раз, когда вызывается вывод журнала, он будет заключен в loggingEvent и кэширован. Из первой и второй точек на приведенном выше рисунке видно, что эта очередь кэша логов занимает очень большой объем памяти, и только на его объект loggingEvent приходится около 23% памяти, боже мой. Окно наблюдения инспектора в третьей точке на приведенном выше рисунке может отображать конкретное содержимое этого объекта, поэтому мы перехватили сообщение первых двух объектов loggingEvent с наибольшей долей, чтобы увидеть, каково содержимое этого журнала.
После некоторого тщательного изучения автор в основном определил, чтоПроизводитель интерфейса dubbo сообщает, что длина передаваемого контента превышает лимит при возврате результата,而且超出了两个数量级之多。顺藤摸瓜,我们紧跟着从日志内容着手,发现返回的结果 data 是一个数组,也就是在执行批量查询的时候超限了。追溯到对应表的具体批量查询,发现当有一个条件为空时,批量查询语句会跳过sql的in条件去走全表! !然而这个表一共有几十万的数据! ! ! (具体sql在此不表,就是条件筛选没有生效导致)Поставить в известность:
Простое oom действительно не ускользнуло от взора автора. Окончательные качественные причины этого случая таковы:Из-за ошибки проектирования sql объем данных пакетного запроса огромен, что превышает предел передачи dubbo, поэтому выдается исключение и записывается журнал. Объект лога содержит огромное количество специфической информации о возвращаемом запросом объекте и выбрасывается в очередь асинхронного лога, лог не успел сбросить на диск, а память уже лопнула, и oom alarm! !При последующей оптимизации, помимо модификации sql, оптимизируются условия пакетного запроса, а в конфигурацию logback добавляется ограничение на максимальную длину лога для предотвращения возникновения oom, вызванного печатью лога.