Устранение неполадок с использованием памяти JVM

JVM

В последние недели группа часто получала алармы по мониторингу памяти от некоторых сервисных кластеров.На прошлой неделе руководитель решил провести устранение неполадок.Эта задача оказалась в моих руках.Раньше у меня был небольшой опыт в этой области.Я воспользовался этой возможностью поставить книгу на "знание" сочетается с практикой и дорабатывается в статью.

описание проблемы

  • После каждого выпуска использование памяти службой кластера составляет менее 50 %, а при работе оно будет увеличиваться до более чем 94 %.
  • Процесс Java в служебной части зависнет, и модуль перезапустится.

Процесс устранения неисправностей

В соответствии с явлением немного выше моего предварительного процесса расследования

  • Просмотр состояния памяти, отслеживаемого кластером K8S
  • Просмотр распределения ресурсов модуля службы
  • Просмотр параметров запуска JVM процесса службы Java в модуле
  • Проверьте ситуацию с восстановлением памяти и обратите внимание на наличие каких-либо явных отклонений от нормы.
  • Используйте jmap для экспорта файлов дампа для анализа
  • Определите местоположение кода проблемы в соответствии с причиной, проанализированной файлом дампа
  • Правильная тенденция использования памяти после оптимизации

1. Просмотр состояния памяти, отслеживаемого кластером K8S.

ЭтопроблемаКластер службы K8S отслеживает диаграмму динамики памяти. Из графика видно, что даже при небольших колебаниях объема памяти использование имеет тенденцию к росту.

2. Просмотрите выделение ресурсов K8S для модуля.

# 执行命令查看该pod的资源分配情况
kubectl --kubeconfig ${source_config} -n ${namespace} describe pod ${pod_name}

Размер памяти запроса и ограничения: память 8G

3. Просмотрите параметры JVM запуска для процесса обслуживания Java в POD

Если веб-контейнер встроен в проект SpringBoot, вы можете сначала войти в модуль, а затем использовать следующие два параметра для просмотра параметров JVM.

# 查看已经启动的java服务参数
ps -ef | grep java
# 使用jinfo查看
jinfo -flags ${pid}

Мои услуги-Xms5769m -Xmx5769m -Xmn2884mДругие параметры опущены, и здесь есть проблема: наша диаграмма мониторинга памяти показывает, что текущее использование составляет 7,13 ГБ, но память нашей кучи настроек JVM намного меньше этого значения.

4. Проверьте восстановление памяти и обратите внимание на наличие каких-либо явных отклонений.

Общее использование памяти контейнером является нормальным, а колебания представляют собой память до и после перезапуска.

Вы также можете использовать другие команды jvm для просмотра памяти в определенный момент в модуле, или вы можете напрямую просмотреть журнал gc для общего анализа.

# 每refresh_time毫秒打印一次内存使用情况gc次数等
jstat -gc ${pid} ${refresh_time}
# 你查看时刻的内存使用情况
jmap -heap ${pid}

Наша память JVM является нормальным значением, указывающим на то, что память вне стека занята, используйтеtopувидеть нижеЗдесь есть дыра,usedСуммарное значение — это значение модуля кластера, а не модуля.Когда я проверил этот пункт, я чуть не подумалPrometheusЕсть проблема с щупом, допросGrafanaПредставлены данные мониторинга достоверности. После тщательного наблюдения было обнаружено, что значение RES аналогично 7,13 ГБ памяти на графике мониторинга памяти в этот момент, что указывает на то, что зонд в порядке. На момент разбора пришел к выводу, что память в куче сервиса в норме.Может проблема с использованием памяти вне кучи? Продолжайте исследовать этот вопрос.

5. Используйте JMAP для экспорта файлов дампа для анализа

Сначала сгенерируйте файл дампа в этот момент

jmap -dump:live,format=b,file=${dump_name}.bin ${PID}

скачатьMAT, открыть для анализа файла дампа, выбратьLeak Suspects.

Вы видите 539 объектов потока, почему служба создает так много?

открыть thread_overview Префикс XNIO-2 для этого пула потоков успешно привлек мое внимание, я обнаружил, что этот поток отфильтрован для создания 320, он был заблокирован живым. Пул потоков с префиксом I/O-dispatch также успешно привлек мое внимание: после фильтрации я обнаружил, что было создано 120 потоков, и они все еще были заблокированы.

6. Определите местоположение кода проблемы в соответствии с причинами, проанализированными файлом дампа.

Пул потоков XNIO-2, очень знакомое название, он как будто поет мне: Мы вроде где-то встречались, помнишь? эмммм, я действительно не могу вспомнить, но я знаю, что вы не должны быть пулом потоков, который я определил, потому что я укажу имя. тогдаgrepсервисный лог, нашелundertowКонтейнер печатает при запуске.

ОткрытымundertowИсходный код контейнера:

ioThreads = 默认值得逻辑核数
workerThreads = ioThreads * 8

Выше мы видели, что k8s указывает, что процессор pod'а — 1C, а согласно приведенным выше 320 потокам он должен быть 40C. Войдите в модуль с этим вопросом и используйтеlscpuПроверьте количество логических ядер процессора.

Я обнаружил, что логический номер ядра действительно равен 40C, и спросил:CDGroup сказали, что при запуске некоторых подов будет происходить такая ситуация, а количество прочитанных логических ядер подов — это логические ядра общего пула ресурсов этого сервиса. Глядя в конфигурационный файл сервиса, не указан размер потока подвода, поэтому настраиваем его:

server.undertow.io-threads= io线程数
server.undertow.worker-threads= 工作线程数

Стек вызовов epollWait на первый взгляд связан с nio.После размышлений о внутренней части сервиса, кроме undertow будет использоваться только rpc.Посмотрев конфигурацию rpc, worker по умолчанию равен 120, что явно неразумно, и она снижена до 16.

7. Исправьте тенденцию использования памяти после оптимизации

После перезапуска онлайн-наблюдения в течение нескольких дней, использование всей памяти обслуживания стала нормальной.

Общая тенденция заключается в том, что память всегда меньше, чем 5,7 ГБ, настроенные JVM, и нет такой ситуации, когда 1 имеет тенденцию к увеличению в целом.

Суммировать:

  • В этой статье описывается особый случай, когда количество ядер pod не является нормальным, что приводит к постоянному использованию памяти вне кучи.
  • О том, почему NIO ждет нового потребления в парке, вы можете прочитать в моей предыдущей статье о модели потока NIO ("Углубленный чат о NIO").
  • Идея проблемы JVM, я думаю, дело в этом процессе, но можно определить проблему заранее на определенном шаге, например, частый GC, или слишком много старческих объектов и т. д. Может быть, при анализе Журнал GC Подтверждено, но конкретный код позиционирования должен быть проанализирован из файла DUMP.
  • После этой корректировки общее использование ресурсов памяти сократилось почти на 40%, что позволило сэкономить много ресурсов для нашего отдела.

Ссылки по теме