Путь к практике настройки JVM в сценариях с высокой степенью параллелизма

Java JVM оптимизация производительности
Путь к практике настройки JVM в сценариях с высокой степенью параллелизма

1. Предпосылки

В феврале 2021 года были получены отзывы о том, что определенный основной интерфейс видеоприложения имел медленную реакцию в период пиковой нагрузки, что повлияло на работу пользователей.

В ходе мониторинга было обнаружено, что медленный отклик интерфейса в основном вызван большим потреблением времени P99, что, как предполагается, связано с GC службы.Типичный пример производительности службы GC выглядит следующим образом:

Видно, что за период наблюдения:

  • Среднее количество юных ГК за 10 минут — 66, пиковое — 470;

  • Среднее количество полных GC за 10 минут — 0,25, а пиковое — 5;

Видно, что Полное GC встречается очень часто, а Young GC также чаще встречается в определенный период, так что есть большой простор для оптимизации. Поскольку оптимизация паузы сборщика мусора является эффективным средством уменьшения задержки P99 интерфейса, было принято решение выполнить настройку JVM для этой основной службы.

2. Цели оптимизации

  • Задержка интерфейса P99 уменьшена на 30%

  • Уменьшите количество Young GC и Full GC, продолжительность паузы и продолжительность одной паузы

Поскольку поведение GC связано с параллелизмом, например, когда параллелизм относительно высок, независимо от того, как выполняется настройка, молодой GC всегда будет очень частым, и всегда будут объекты, которые не следует продвигать для срабатывания Полный сборщик мусора, поэтому цели оптимизации формулируются в зависимости от нагрузки:

Цель 1: Высокая нагрузка (более 1000 запросов в секунду для одной машины)

  • Количество Молодых ГК снижается на 20-30%, а накопленное время Молодых ГК не ухудшается;

  • Количество полных сборщиков мусора уменьшено более чем на 50 %, время, необходимое для одного и совокупного полного сборщика мусора, сокращено более чем на 50 %, а выпуск службы не запускает полный сбор мусора.

Цель 2: Средняя нагрузка (одна машина 500-600)

  • Количество юных ГК уменьшено на 20%-30%, а суммарное время юных ГК уменьшено на 20%;

  • Количество полных сборок — не более 4 раз в сутки, а сервисный релиз не запускает полную сборку.

Цель 3: Низкая нагрузка (менее 200 запросов в секунду для одной машины)

  • Количество юных ГК уменьшено на 20%-30%, а суммарное время юных ГК уменьшено на 20%;

  • Количество Full GC — не более 1 раза в сутки, а сервисный релиз не запускает Full GC.

3. Текущие проблемы

Параметры конфигурации JVM для текущего сервиса следующие:

-Xms4096M -Xmx4096M -Xmn1024M
-XX:PermSize=512M
-XX:MaxPermSize=512M

Из чисто параметрического анализа выявляются следующие проблемы:

**Указанный коллектор не показан **

Сборщиком JDK 8 по умолчанию является ParrallelGC, то есть Parallel Scavenge используется в области Young, а Parallel Old — для сбора в старом поколении.Эта конфигурация характеризуется приоритетом пропускной способности, что в целом подходит для фоновых серверов задач.

Например, пакетная обработка заказов, научные вычисления и другие сценарии, чувствительные к пропускной способности, но нечувствительные к задержке, текущая служба представляет собой портал для видео и взаимодействия с пользователем, который очень чувствителен к задержке, поэтому не подходит для использования сборщик по умолчанию ParrallelGC, который должен быть более подходящим.

Необоснованное соотношение Молодого Района

Текущая служба в основном предоставляет API.Характеристики этого типа службы заключаются в том, что резидентных объектов меньше, и у большинства объектов относительно короткий жизненный цикл, и они умрут после одного или двух молодых GC.

Взгляните на текущую конфигурацию JVM.:

Вся куча 4G, область Young всего 1G, значение по умолчанию -XX:SurvivorRatio=8, то есть эффективный размер 0,9G, а размер резидентного объекта в старости около 400M.

Это означает, что при высокой нагрузке на сервис и большом параллелизме запросов область Eden + S0 в области Young будет быстро заполняться, и GC Young будет выполняться чаще.

Кроме того, это приведет к преждевременному продвижению объектов, которые должны быть возвращены Young GC, увеличит частоту полного GC, а также увеличит площадь, собираемую за один раз.Поскольку в старой области используется ParralellOld, ее нельзя выполнять одновременно с пользовательских потоков, что приводит к увеличению времени обслуживания.Время останавливается, доступность снижается, а время отклика P99 увеличивается.

не задано

-XX:MetaspaceSize и -XX:MaxMetaspaceSize

Perm区在jdk 1.8已经过时,被Meta区取代,
因此-XX:PermSize=512M -XX:MaxPermSize=512M配置会被忽略,
真正控制Meta区GC的参数为
-XX:MetaspaceSize:
Metaspace初始大小,64位机器默认为21M左右
 
-XX:MaxMetaspaceSize:
Metaspace的最大值,64位机器默认为18446744073709551615Byte,
可以理解为无上限
 
-XX:MaxMetaspaceExpansion:
增大触发metaspace GC阈值的最大要求
 
-XX:MinMetaspaceExpansion:
增大触发metaspace GC阈值的最小要求,默认为340784Byte

Таким образом, в процессе запуска и публикации службы, когда область метаданных достигает 21M, будет запущен полный GC (порог GC метаданных), а затем с расширением области метаданных несколько полных GC (порог GC метаданных). ) будут смешаны, что приведет к снижению стабильности и эффективности выпуска службы.

Кроме того, если служба использует множество технологий динамического создания классов, она также будет генерировать ненужный полный GC (пороговое значение GC метаданных) из-за этого механизма.

4. Схема оптимизации/схема проверки

Очевидные недостатки текущей конфигурации были проанализированы выше.Следующий план оптимизации в основном целенаправленно решает эти проблемы, а затем решает, следует ли продолжать глубокую оптимизацию на основе эффекта.

Текущие основные / отличные коллекционеры включают:

  • Parrallel Scavenge + Parrallel Old: приоритет пропускной способности, подходящий для служб фоновых задач;

  • ParNew + CMS: классический коллектор с малой паузой, используемый большинством коммерческих и чувствительных к задержке сервисов;

  • G1: сборщик JDK 9 по умолчанию, когда куча памяти относительно велика (выше 6G-8G), он показывает относительно высокую пропускную способность и короткое время паузы;

  • ZGC: сборщик мусора с малой задержкой, представленный в JDK 11, в настоящее время находится на экспериментальной стадии;

В сочетании с реальной ситуацией с текущим сервисом (размер кучи, ремонтопригодность) для нас более целесообразно выбрать решение ParNew + CMS.

Принцип подбора параметров следующий:

1) Необходимо указать размер метаобласти, а размер MetaspaceSize и MaxMetaspaceSize должен быть одинаковым. Конкретный размер зависит от онлайн-экземпляра. Вы можете получить онлайн-экземпляр службы с помощью jstat -gc.

# jstat -gc 31247
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
37888.0 37888.0 0.0 32438.5 972800.0 403063.5 3145728.0 2700882.3 167320.0 152285.0 18856.0 16442.4 15189 597.209 65 70.447 667.655

Видно, что MU составляет около 150M, так что -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M более разумно.

2) Молодняк не настолько велик, насколько это возможно.

Когда размер кучи постоянен, чем больше область Young, тем меньше будет частота Young GC, но старая область станет меньше.Если она слишком мала, небольшое продвижение некоторых объектов вызовет Full GC .

Если Молодая область слишком мала, Молодой GC будет чаще, поэтому Старая область будет больше, а пауза одного Полного GC будет больше. Следовательно, необходимо сравнить размер области Янга в нескольких сценариях в зависимости от ситуации обслуживания, и, наконец, получить наиболее подходящую конфигурацию.

Основываясь на вышеизложенных принципах, можно выделить 4 комбинации параметров:

1.ParNew +CMS, площадь Юнга удваивается

-Xms4096M -Xmx4096M -Xmn2048M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+CMSScavengeBeforeRemark

**2.ParNew +CMS, **Молодняк удваивается,

Удалите -XX:+CMSScavengeBeforeRemark (с помощью параметра [-XX:CMSScavengeBeforeRemark] можно выполнить сборку мусора нового поколения перед перемаркировкой).

Поскольку между объектами в старом поколении и молодом поколении существуют ссылки между поколениями, молодое поколение также будет сканироваться, когда в старом поколении выполняется отслеживание корней GC. меньше.Для некоторых объектов производительность этапа маркировки также может быть улучшена. )

-Xms4096M -Xmx4096M -Xmn2048M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC

3.ParNew +CMS, Young зона расширена в 0,5 раза

-Xms4096M -Xmx4096M -Xmn1536M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC 
-XX:+CMSScavengeBeforeRemark

4.ParNew +CMS, Young area без изменений

-Xms4096M -Xmx4096M -Xmn1024M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC 
-XX:+CMSScavengeBeforeRemark

Далее нам нужно сравнить, проанализировать и проверить фактическую производительность четырех решений при разных нагрузках в среде стресс-теста.

4.1 Проверка/анализ среды стресс-тестирования

Сценарий высокой нагрузки (1100 запросов в секунду) Производительность GC

Видно, что в сценариях с высокой нагрузкой производительность четырех индикаторов ParNew + CMS намного лучше, чем у Parallel Scavenge + Parrallel Old. в:

  • Схема 4 (область Юнга расширена в 0,5 раза) работает лучше всего, задержки интерфейсов P95 и P99 уменьшены на 50% по сравнению с текущей схемой, суммарное время Full GC уменьшено на 88%, количество Young GC уменьшается на 23 %, а совокупное время юного GC уменьшается на 4 %. также увеличивается, что соответствует ожиданиям.

  • Две схемы, в которых область Юнга удваивается, а именно схема 2 и схема 3, имеют сходную производительность.Задержки интерфейса P95 и P99 уменьшены на 40% по сравнению с текущей схемой, совокупное время полного GC уменьшено на 81%. , а количество Янг ​​GC уменьшается на 43%.Суммарное время на GC сокращается на 17%, что немного меньше, чем расширение области Юнга в 0,5 раза.Общая производительность хорошая.Две схемы слились и больше не различаются.

Неизменная схема в Молодом районе показала худшие результаты в новой схеме и была исключена. Таким образом, в сценарии средней нагрузки нам нужно только сравнить схему 2 и схему 4.

Сценарий средней нагрузки (600 запросов в секунду) Производительность GC

Видно, что в сценарии средней нагрузки показатели двух ParNew + CMS (схема 2 и схема 4) также намного лучше, чем у Parallel Scavenge + Parrallel Old.

  • Лучше всего показало себя решение с удвоением области Юнга, по сравнению с текущим решением задержки интерфейсов P95 и P99 снижены на 32%, суммарное время Full GC уменьшено на 93%, уменьшено количество Young GC на 42%, а кумулятивное время Юнга ГК сократилось на 44%;

  • Расширение в 0,5 раза у Молодого района чуть меньше.

В целом производительность двух схем очень близка.В принципе обе схемы приемлемы.Однако схема с 0,5-кратным расширением области Юнга лучше работает в период пиковой активности.Для обеспечения стабильности и производительности услуги в пиковый период, текущее предпочтение При выборе ParNew + CMS область Young расширяется в 0,5 раза.

4.2 Схема оттенков серого/анализ

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

Целевая группа xx.xxx.60.6

Принять схему 2, целевая схема

-Xms4096M -Xmx4096M -Xmn1536M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC 
-XX:+CMSScavengeBeforeRemark

Группа управления 1 xx.xxx.15.215

использовать оригинальный план

-Xms4096M -Xmx4096M -Xmn1024M
-XX:PermSize=512M
-XX:MaxPermSize=512M

Контрольная группа 2 хх.ххх.40.87

Принять схему 4, которая является целевой схемой-кандидатом

-Xms4096M -Xmx4096M -Xmn2048M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC 
-XX:+CMSScavengeBeforeRemark

Машины в оттенках серого 3.

Давайте сначала проанализируем показатели, связанные с Young GC:

Молодые времена GC

Суммарное время молодого GC

Разовый расход Young GC

Видно, что по сравнению с исходной схемой количество YGC целевой схемы уменьшено на 50 %, а совокупное время уменьшено на 47 %. При улучшении пропускной способности значительно снижена частота сервисных пауз, а цена — увеличение времени, затрачиваемого на один GC Young, 3 мс, польза очень высока.

Общая производительность схемы сравнения 2, то есть схемы 2G в районе Юнга, немного уступает целевой схеме, и далее анализируется показатель Full GC.

Рост памяти в старости

Полное время GC

Полное совокупное/однократное потребление GC

По сравнению с исходной схемой при использовании целевой схемы скорость прироста старости значительно медленнее, в основном количество случаев Полного ГК за период наблюдения снижается со 155 до 27 раз, снижение на 82%, а среднее время паузы уменьшено с 399мс до 60мс., уменьшено на 85%, а также очень меньше заусенцев.

По общей эффективности схема управления 2, схема Young District 2G, уступает целевой схеме. На этом этапе видно, что целевое решение намного превосходит исходное решение по всем параметрам, и цель оптимизации в основном достигнута.

Но внимательные студенты обнаружат, что целевое решение более стабильно, чем исходное решение, «Полный сборщик мусора» (фактически Фоновый сборщик мусора CMS), но после каждого «Полного сбора мусора» будет появляться очень трудоемкий глюк. в этот момент запрос будет приостановлен на 2-3 секунды. Можно ли его дополнительно оптимизировать, чтобы дать пользователю более экстремальный опыт?

4.3 Повторная оптимизация

Здесь мы сначала анализируем логику этого явления.

Для парсера CMS используется алгоритм парсинга Mark-Sweep-[Compact].

Типы CMS Collector GC:

CMS Background GC

Этот CMS GC является наиболее распространенным типом, является циклическим, запускается постоянным потоком, регулярно сканирует использование старой JVM, когда использование превышает пороговое значение, с использованием режима Mark-Sweep, отсутствие этого компактного вида трудоемкой операции, и может обрабатываться параллельно с пользователем, поэтому пауза CMS будет относительно низкой, в журналах GC появится GC (CMS Initial Mark) было слово от имени CMS Background GC.

Поскольку Background GC использует Mark-Sweep, это приведет к фрагментации памяти в старости, что также является самой большой слабостью CMS.

CMS Foreground GC

Такой сборщик мусора является полным сборщиком мусора в полном смысле слова CMS-сборщик.Он собирается с использованием Serial Old или Parralel Old, и частота возникновения низкая.Когда это происходит, это вызывает большую паузу.

Существует много сценариев, которые запускают CMS Foreground GC.

  • Система.gc();

  • jmap -histo: текущий pid;

  • Недостаточно места в области метаданных;

  • Продвижение не удается, и флаг в журнале GC является Parnew (продвижение не удалось);

  • Сбой в параллельном режиме, флаг в журнале GC указывает на сбой в параллельном режиме.

Нетрудно сделать вывод, что сбой в целевом решении вызван сбоем продвижения или сбоем параллельного режима.Поскольку онлайн-печать журналов gc не включена, это не имеет значения, потому что первопричины этих двух сценарии те же, то есть несколько CMS Backgroud GCs Старая фрагментация памяти, вызванная позже.

Нам нужно только свести к минимуму сбои продвижения и сбои параллельного режима, вызванные шардами старого поколения.

Фоновый сборщик мусора CMS регулярно сканируется резидентным потоком JVM на предмет коэффициента использования старого возраста. Когда коэффициент использования превышает пороговое значение, порог управляется двумя параметрами -XX:CMSInitiatingOccupancyFraction; -XX:+UseCMSInitiatingOccupancyOnly.If не задано, по умолчанию в первый раз установлено значение 92. %, последующие действия будут делать прогнозы и динамические корректировки на основе исторических условий.

Если мы зафиксируем размер порога и установим порог на относительно разумное значение, это не сделает GC слишком частым, но также уменьшит вероятность сбоя продвижения или сбоя параллельного режима, что может значительно снизить частоту сбоев.

Распределение кучи целевой схемы выглядит следующим образом:

  • Молодой район 1.5G

  • Старая зона 2.5G

  • Жилые объекты в Старом районе около 400м

По эмпирическим данным 75% и 80% являются компромиссом, поэтому выбираем -XX:CMSInitiatingOccupancyFraction=75 -

XX:+UseCMSInitiatingOccupancyOnly для наблюдения в градациях серого (мы также провели контрольный эксперимент на 80% сцен, 75% лучше, чем 80%).

Конфигурация окончательного целевого сценария:

-Xms4096M -Xmx4096M -Xmn1536M 
-XX:MetaspaceSize=256M 
-XX:MaxMetaspaceSize=256M 
-XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC 
-XX:+CMSScavengeBeforeRemark 
-XX:CMSInitiatingOccupancyFraction=75 
-XX:+UseCMSInitiatingOccupancyOnly

Сконфигурировано как указано выше, оттенки серого xx.xxx.60.6 один компьютер;

По результатам повторной оптимизации глюки, вызванные CMS Foreground GC, в основном исчезли, что соответствует ожиданиям.

Таким образом, конечная целевая схема видеоуслуги имеет следующую конфигурацию;

-Xms4096M -Xmx4096M -Xmn1536M 
-XX:MetaspaceSize=256M 
-XX:MaxMetaspaceSize=256M 
-XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC 
-XX:+CMSScavengeBeforeRemark 
-XX:CMSInitiatingOccupancyFraction=75 
-XX:+UseCMSInitiatingOccupancyOnly

5. Принятие результатов

Оттенки серого длится около 7 дней, охватывая будние и выходные дни.Результаты соответствуют ожиданиям, поэтому он соответствует условиям для открытия полного объема онлайн.Ниже приводится оценка результатов после полного объема.

Молодые времена GC

Суммарное время молодого GC

Время, потраченное на один Young GC

Судя по показателям ГК Юнга, после корректировки количество ГК Юнга уменьшается в среднем на 30%, суммарное время ГК Юнга уменьшается в среднем на 17%, а среднее время одного ГК Юнга увеличивается на около 7 мс Производительность Young GC соответствует ожиданиям.

Помимо технических средств, мы также сделали некоторые оптимизации в бизнесе.Будут явные и нерегулярные глюки в Young GC экземпляра перед настройкой (задание по расписанию не обязательно назначается текущему экземпляру).Вот запланированное Будет загружен большой объем данных, задача будет разбита на сегменты и распределена по нескольким экземплярам в процессе настройки, что сделает Young GC более плавным.

Полное GC одиночное/кумулятивное время

От показателя "Полная сборка" частота и паузы "Полная сборка" сильно снижены.Можно сказать, что полной сборки в прямом смысле нет в принципе.

Основной интерфейс-A (больше нисходящих зависимостей) Время отклика P99 уменьшено на 19% (с 3457 мс до 2817 мс);

Основной интерфейс-B (нисходящая зависимая среда) Время отклика P99 уменьшено на 41% (с 1647 мс до 973 мс);

Core Interface-C (наименее нисходящие зависимости) Время отклика P99 уменьшено на 80% (с 628 мс до 127 мс);

В совокупности общий результат превзошел все ожидания. Производительность Young GC очень соответствует поставленным целям.Полного GC в прямом смысле в принципе нет.Эффект оптимизации интерфейса P99 зависит от количества нижестоящих зависимостей.Чем меньше зависимостей,тем заметнее эффект.

6. Пишите в конце

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

В этой статье, основанной на опыте настройки видеосервисов, основное внимание уделяется идее и процессу реализации настройки, а также обобщению некоторых общих процессов настройки в надежде предоставить вам некоторую справочную информацию.

Авторы: Ли Гуаньюнь, Джессика Чен, vivo Internet Technology Team