Предисловие
Фон
Был в магазине Java. Целые месяцы были посвящены проведению тестов производительности в распределенных системах, основные приложения были на Java Некоторые из которых подразумевают продукты, разработанные и продаваемые самим Sun (тогда Oracle).
Я перейду к урокам, которые я выучил, немного истории о JVM, немного разговоров о внутренностях, пару объясненных параметров и, наконец, некоторую настройку. Попытка держать это в точке, чтобы вы могли применить это на практике.
В мире Java все быстро меняется, поэтому его часть может быть уже устаревшей с прошлого года, когда я все это делал. (Java 10 уже вышла?)
Хорошая практика
Что вы ДОЛЖНЫ делать: эталон, эталон, ЭТАЛОН!
Когда вам действительно нужно знать о производительности, вам необходимо выполнить реальные тесты, специфичные для вашей рабочей нагрузки. Альтернативы нет.
Также, вы должны следить за JVM. Включить мониторинг. Хорошие приложения обычно предоставляют веб-страницу мониторинга и / или API. В противном случае есть общие инструменты Java (JVisualVM, JMX, hprof и некоторые флаги JVM).
Имейте в виду, что при настройке JVM производительность обычно не увеличивается. Это скорее "сбой или не сбой, найти точку перехода" . Речь идет о том, чтобы знать, что когда вы предоставляете такое количество ресурсов вашему приложению, вы можете последовательно ожидать , что количество исполнений взамен. Знание - сила.
Представления в основном определяются вашим приложением. Если вы хотите быстрее, вы должны написать лучший код.
Что вы будете делать большую часть времени: жить с надежными чувствительными значениями по умолчанию
У нас нет времени на оптимизацию и настройку каждого отдельного приложения. Большую часть времени мы будем просто жить с разумными значениями по умолчанию.
Первое, что нужно сделать при настройке нового приложения, это прочитать документацию. Большинство серьезных приложений поставляется с руководством по настройке производительности, включая рекомендации по настройке JVM.
Затем вы можете настроить приложение: JAVA_OPTS: -server -Xms???g -Xmx???g
-server
: включить полную оптимизацию (в настоящее время этот флаг является автоматическим на большинстве JVM)
-Xms
-Xmx
: установите минимальную и максимальную кучу (всегда одинаковое значение для обоих, это единственная оптимизация, которую нужно сделать).
Отлично, вы знаете обо всех параметрах оптимизации, которые нужно знать о JVM, поздравляем! Это было просто: D
Чего ВЫ НЕ ДОЛЖНЫ делать, КОГДА-ЛИБО:
Пожалуйста, НЕ копируйте случайные строки, которые вы нашли в Интернете, особенно если они занимают несколько строк, например:
-server -Xms1g -Xmx1g -XX:PermSize=1g -XX:MaxPermSize=256m -Xmn256m -Xss64k -XX:SurvivorRatio=30 -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=10 -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark -XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -Dsun.net.inetaddr.ttl=5 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=`date`.hprof -Dcom.sun.management.jmxremote.port=5616 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -server -Xms2g -Xmx2g -XX:MaxPermSize=256m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC
Например, эта вещь, найденная на первой странице Google, просто ужасна. Есть аргументы, указанные несколько раз с конфликтующими значениями. Некоторые просто принудительно устанавливают значения по умолчанию для JVM (в конце концов это значения по умолчанию из 2 версий JVM назад). Некоторые из них устарели и просто игнорируются. И, наконец, по крайней мере один параметр настолько недействителен, что он будет постоянно приводить к сбою JVM при запуске из-за его простого существования.
Фактическая настройка
Как выбрать размер памяти:
Прочтите руководство из вашего приложения, оно должно дать некоторые указания. Контролировать производство и корректировать впоследствии. Выполните несколько тестов, если вам нужна точность.
Важное примечание : Процесс java займет до max heap PLUS 10% . Издержки X% - это управление кучей, не включенное в саму кучу.
Вся память обычно предварительно выделяется процессом при запуске. Вы можете увидеть процесс, используя максимальную кучу ВСЕ ВРЕМЯ. Это просто неправда. Вам необходимо использовать инструменты мониторинга Java, чтобы увидеть, что на самом деле используется.
Нахождение нужного размера:
- Если происходит сбой с OutOfMemoryException, недостаточно памяти
- Если с OutOfMemoryException не произойдет сбой, значит, слишком много памяти
- Если памяти слишком много, НО аппаратное обеспечение получило и / или уже оплачено, это совершенное число, работа выполнена!
JVM6 - бронза, JVM7 - золото, JVM8 - платина ...
JVM постоянно улучшается. Сборка мусора - очень сложная вещь, и над ней работает много очень умных людей. За последнее десятилетие в нем произошли огромные улучшения, и он будет и впредь.
В ознакомительных целях. Это как минимум 4 доступных сборщика мусора в Oracle Java 7-8 (HotSpot) и OpenJDK 7-8. (Другие JVM могут быть совершенно другими, например, Android, IBM, встроенные):
- SerialGC
- ParallelGC
- ConcurrentMarkSweepGC
- G1GC
- (плюс варианты и настройки)
[Начиная с Java 7 и далее. Код Oracle и OpenJDK частично используются совместно. GC должен быть (в основном) одинаковым на обеих платформах.]
JVM> = 7 имеют много оптимизаций и выбирают приличные значения по умолчанию. Это немного меняется в зависимости от платформы. Это балансирует несколько вещей. Например, решение включить многоядерные оптимизации или нет, если процессор имеет несколько ядер. Вы должны позволить этому сделать это. Не изменять и не форсировать настройки ГХ.
Это нормально, что компьютер принимает решение за вас (для этого и нужны компьютеры). Лучше иметь настройки JVM всегда оптимальными на 95%, чем принудительно устанавливать «всегда агрессивный сбор из 8 ядер для меньшего времени паузы» на всех блоках, половина из которых в конце равна t2.small.
Исключение : когда приложение поставляется с руководством по производительности и определенной настройкой на месте. Можно оставить все настройки как есть.
Подсказка : Переход на более новую JVM, чтобы воспользоваться последними улучшениями, иногда может обеспечить хороший прирост без особых усилий.
Особый случай: -XX: + UseCompressedOops
JVM имеет специальную настройку, которая вызывает внутреннее использование 32-битного индекса (читай: как указатели). Это позволяет адресовать 4 294 967 295 объектов * адрес 8 байтов => 32 ГБ памяти. (НЕ путать с адресным пространством 4 ГБ для указателей REAL).
Снижает общее потребление памяти с потенциальным положительным влиянием на все уровни кэширования.
Пример из реальной жизни : в документации ElasticSearch говорится, что работающий 32-битный узел 32 ГБ может быть эквивалентен 64-битному узлу 40 ГБ с точки зрения фактических данных, хранящихся в памяти.
Заметка по истории : Известно, что флаг был нестабильным в эпоху до Java-7 (возможно, даже до-Java-6). Некоторое время он отлично работал в новой JVM.
Повышение производительности виртуальной машины Java HotSpot ™
[...] В Java SE 7 использование сжатых опций является значением по умолчанию для 64-разрядных процессов JVM, когда -Xmx не указан и для значений -Xmx менее 32 гигабайт. Для JDK 6 до выпуска 6u23 используйте флаг -XX: + UseCompressedOops с командой java, чтобы включить эту функцию.
См. : И снова JVM загорается на годы вперед по сравнению с ручной настройкой. Тем не менее, об этом интересно знать =)
Особый случай: -XX: + UseNUMA
Неоднородный доступ к памяти (NUMA) - это конструкция памяти компьютера, используемая в многопроцессорной обработке, время доступа к памяти зависит от расположения памяти относительно процессора. Источник: Википедия
Современные системы имеют чрезвычайно сложную архитектуру памяти с несколькими уровнями памяти и кэшей, как частными, так и общими, для ядер и ЦП.
Совершенно очевидно, что доступ к данным в кеше L2 в текущем процессоре ОЧЕНЬ быстрее, чем полный переход к карте памяти из другого сокета.
Я полагаю, что все системы с несколькими сокетами , продаваемые сегодня, являются NUMA по дизайну, в то время как все потребительские системы НЕ. Проверьте, поддерживает ли ваш сервер NUMA с помощью команды numactl --show
в Linux.
Флаг с поддержкой NUMA указывает JVM оптимизировать распределение памяти для базовой аппаратной топологии.
Увеличение производительности может быть значительным (то есть две цифры: + XX%). Фактически, кто-то, переключающийся с «NOT-NUMA 10CPU 100GB» на «NUMA 40CPU 400GB», может испытать [драматическую] потерю производительности, если он не знает о флаге.
Примечание : Есть обсуждения для определения NUMA и автоматической установки флага в JVM http://openjdk.java.net/jeps/163
Бонус : Все приложения, предназначенные для работы на больших аппаратных средствах (например, NUMA), должны быть оптимизированы для этого. Это не характерно для приложений Java.
Навстречу будущему: -XX: + UseG1GC
Последнее усовершенствование в сборке мусора - G1 сборщик (читай: Garbage First) .
Предназначен для систем с высоким ядром и высокой памятью. На абсолюте минимум 4 ядра + 6 ГБ памяти. Он предназначен для баз данных и приложений, интенсивно использующих память, используя в 10 раз больше.
Короткая версия, при таких размерах традиционные ГХ сталкиваются с слишком большим количеством данных для одновременной обработки и паузы выходят из-под контроля. G1 разделяет кучу на множество небольших секций, которыми можно управлять независимо и параллельно во время работы приложения.
Первая версия была доступна в 2013 году. Она достаточно зрелая для производства, но в ближайшее время она не будет работать по умолчанию. Это стоит попробовать для больших приложений.
Не трогать: Размеры генерации (NewGen, PermGen ...)
ГХ разбил память на несколько секций. (Не вдаваясь в подробности, вы можете гуглить "Java GC Generations".)
В последний раз я тратил неделю на то, чтобы попробовать 20 различных комбинаций флагов поколений в приложении со скоростью 10000 ударов в секунду. Я получал великолепное повышение от -1% до +1%.
Поколения Java GC - интересная тема для чтения или написания статей. Их нельзя настраивать, если только вы не являетесь частью 1%, которые могут посвятить значительное время незначительным выгодам среди 1% людей, которые действительно нуждаются в оптимизации.
Заключение
Надеюсь, это поможет вам. Веселитесь с JVM.
Java - лучший язык и лучшая платформа в мире! Иди распространяй любовь: D