Оптимизация производительности Java в AIX: Часть 5. Ссылки и заключение

Данная статья является заключительной в цикле из пяти статей, содержащих советы и методики, используемые для настройки максимальной производительности Java™-приложений в AIX®. Мы затронули ряд интересных аспектов в настройке производительности Java на AIX, изучили ряд примеров, и в конце этого цикла приведем список полезных ссылок.

Амит Матюр, ведущий технический консультант и менеджер по реализации решений, IBM

Амит Матюр (Amit Mathur) работает в группе IBM Solutions Development, занимаясь в основном IBM ISV и возможностями/производительностью приложений на платформе IBM eServer, а также оказывая поддержку пользователям ISV. Пишет статьи и учебные пособия для developerWorks. Амит имеет более чем 14-летний опыт по поддержке разработчиков программного обеспечения и программирования на C/C++, Java, а также баз данных в UNIX и Linux. Он получил степень бакалавра технических наук в области электроники и телекомунникаций в Индии. Связаться с ним можно по адресу amitmat@us.ibm.com.



Сумит Чаула, сертифицированный IT-архитектор IBM и руководитель технической группы, Java Enablement, IBM

Самит Чаула (Sumit Chawla) руководит инициативной группой Java Enablement для IBM eServer (для AIX, Windows и Linux), а также работает консультантом в организации Independent Software Vendors по направлению серверов IBM. Самит имеет степень магистра в области вычислительной техники, обладает более чем 10-летним опытом работы в IT-индустрии, сертифицирован IBM по курсу Application Architect. Он часто пишет статьи для раздела developerWorks eServer. С ним можно связаться по адресу sumitc@us.ibm.com.



29.09.2009

Введение

Данная статья является последней в цикле из пяти статей о производительности Java. Первая статья из этого цикла содержала основы настройки производительности, в статьях 2, 3 и 4 рассматривались различные "узкие места", которые могли повлиять на масштабируемость и пропускную способность системы. Эта статья затрагивает две важных темы, не рассматривавшиеся до этого; кроме того, ниже будут приведены примеры и ссылки на полезные материалы.

В разделе FAQ рассказано о преобразовании переключателей командной строки Sun в переключатели IBM. Кроме того, при любой серьезной настройке производительности, например проведении эталонных тестов системы, необходимо уделять внимание общей настройке системы. Эти темы будут кратко рассмотрены в следующем разделе.

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

Эта статья и весь цикл заканчиваются списком полезных ссылок.


Важные аспекты

В данном разделе рассказывается о преобразовании конфигурации Sun Java в конфигурацию IBM Java и общесистемной настройке AIX-приложений. Поскольку оба затрагиваемых вопроса очень обширны, мы вынуждены ограничиться кратким описанием.

Преобразование переключателей Sun Java

Если исходное приложение было настроено для Sun Java и требуется перенести его на AIX (или любую другую платформу с IBM Java), то, скорее всего, уже пришлось выполнить много трудной работы. Понимание характеристик приложения - это только половина того, что нужно сделать для переноса программы. Можно использовать советы (связанные с характеристиками приложения), рассмотренные во второй и третьей статьях на основе примеров настройки приложений с Sun Java.

Однако мы часто получаем вопросы о том, как преобразовать определенные переключатели командной строки Sun Java в эквивалентные переключатели командной строки IBM Java. Эти выключатели почти всегда относятся к Garbage Collector, так как хорошо настроенный GC жизненно необходим для производительности любого Java-приложения. Преобразование Sun-переключателей в IBM-переключатели - весьма трудоемкое дело из-за различия в архитектуре JVM. IBM Java не содержит Generational Garbage Collector (сборщик мусора, основанный на понятии "поколение объектов") и не понимает никаких переключателей командной строки, которые начинаются с -XX. Архитектура IBM Java "Sovereign" не основана на архитектуре Sun HotSpot. Простейший и в большинстве случаев самый быстрый способ переноса ПО - при выполнении приложения на платформах IBM не использовать все специфичные для Sun опции (в случае необходимости пользоваться опциями IBM). Но если все-таки вас интересует, как преображаются некоторые переключатели Sun в переключатели IBM, читайте эту статью дальше.

В приведенной ниже таблице показано преобразование переключателей командной строки Sun Java GC в эквивалентные переключатели IBM. Это преобразование основано на функциональности переключателей Sun, которая описана в статье "Tuning Garbage Collection with the 1.4.2 Java™ Virtual Machine". Эту таблицу следует использовать только тогда, когда нужно найти эквивалент какого-нибудь переключателя для IBM Java. Следует помнить, что данные переключатели в некоторых случаях не могут заменить переключатели, используемые в операциях по настройке производительности, поскольку у них могут быть, например, различные потребности в размере Java-кучи. Общие советы по настройке GC и IBM Java, а также информацию по этим и другим переключателям GC IBM Java, можно найти в документе "Tuning Garbage Collection with the 1.4.2 Java™ Virtual Machine performance". При создании этой таблицы мы всецело руководствовались справкой по использованию переключателей Sun, которая приведена ниже, но не проводили тесты производительности указанных в таблице переключателей.

Переключатели Sun Эквивалентные переключатели IBM Замечания
-Xms, -Xmx-Xms, -XmxЭти параметры и их значение остались неизменными. Возможно, понадобится подобрать размер кучи.
-XX:SurvivorRatio, -XX:NewSize,
-XX:MaxNewSize, -XX:NewRatio
ОтсутствуютЭти переключатели можно удалить, поскольку они предназначены для generational GC, который не поддерживается IBM Java.
-XX:MinHeapFreeRatio, -XX:MaxHeapFreeRatio-Xminf, -XmaxfДанные переключатели - не единственный способ контролировать расширение/сжатие кучи.
-Xverbose:gc, -XX:+PrintGCDetails-Xverbose:gcФормат подробной трассировки verbosegc IBM Java отличается от Sun GC. Можно активировать более подробную трассировку, но в большинстве случаев достаточно формата verbosegc.
-XX:+UseParallelGC, -Xincgc, -XX:+AggressiveHeapОтсутствуютРазличные типы сборщиков мусора (Garbage Collectors), поддерживаемые Sun. Они не применимы к IBM Java.
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC-Xgcpolicy:optavgpauseБыстрый сборщик мусора, аналогичный по поведению IBM Concurrent Mark GC (но не обязательно по архитектуре).
-XX:+CMSParallelRemarkEnabledОтсутствуютНе используется с IBM Java.
-XX:ParallelGCThreads-XgcthreadsНецелесообразно менять эту настройку для IBM Java.
-Dsun.rmi.dgc.client.gcInterval, -Dsun.rmi.dgc.server.gcInterval-Dsun.rmi.dgc.client.gcInterval, -Dsun.rmi.dgc.server.gcIntervalСм. совет NIO003 в четвертой части.

Как видно из таблицы, в большинстве случаев преобразование переключателей сведется к простому отключению переключателей Sun для работы на платформе IBM. Благодаря этому упражнение по настройке GC упрощается и приносит значительное увеличение производительности.

Общая настройка системы

Инструменты AIX типа schedo и vmo позволяют настраивать систему в целом, поэтому в данном цикле статей они не рассматриваются. Чтобы получить более исчерпывающую информацию об этих инструментах, можно изучить раздел "Ресурсы".

Но для большинства многоуровневых приложений, особенно для эталонных тестов, общая настройка системы неизбежна. Существует несколько отличных ресурсов, которые можно использовать для настройки производительности AIX. Чтобы понять, какой тип настройки нужен, можно ознакомиться с опубликованными аттестационными тестами. Рассмотрим результат теста SpecJBB 2000 с IBM Java на AIX по этой ссылке. В нем были сделаны следующие настройки ОС:

Настройки операционной системы:
  • SPINLOOPTIME=2000
  • vmo -r -o lgpg_regions=256 -o lgpg_size=16777216
  • setsched -S rr -P 40 -p $$
  • schedtune -t 400 -F 1
  • vmtune -S 1

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

Так что же делают настройки, приведенные выше? В документации AIX можно быстро узнать о значении каждой настройки.

Опция SPINLOOPTIME задает число попыток, в течение которых система будет проверять блокировку процесса; после того как все попытки будут исчерпаны, система перейдет к другому процессу. Значение этой опции по умолчанию - 40; более высокое значение укажет системе, что ей следует чуть дольше пытаться снять блокировку процесса. На многопроцессорных системах подобная настройка приведет к увеличению производительности, поскольку проверять блокировку процесса выгоднее, чем переключаться между контекстами процесса.

Строка vmo задает размер и число больших страниц памяти. Если взглянуть на переключатели командной строки Java, можно увидеть, что используется -Xlp. Этот переключатель активирует в Java поддержку больших страниц (более подробно это описано ниже). Если используемое приложение интенсивно использует память, то можно поэкспериментировать с размером страницы памяти - возможно, что это поможет. Более исчерпывающая информация по этой теме доступна в документе SDK Guide, который поставляется вместе с Java.

Строка setsched является сценарием, а не командой AIX. Она вызывает службу ядра thread_setsched и указывает ядру использовать политику планирования с фиксированными приоритетами с выбором процессов для исполнения по очереди, причем у Java-процесса фиксированный приоритет 40.

Команда schedtune также является сценарием для AIX 5.2, передающим параметры новой команде schedo. Данный сценарий устанавливает интервал времени выполнения 400 системных тактов для потоков с фиксированным приоритетом. Из-за этого потоки с фиксированным приоритетом постоянно находятся в глобальной очереди выполнения.

Команда vmtune транслирует свой вызов к эквивалентному вызову команды vmo; сама же команда позволяет фиксировать расположение сегментов общей памяти.

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


Примеры из практики

В этом разделе приведены несколько примеров, взятых из реального опыта команды поддержки Java. Эти примеры - хорошая иллюстрация приемов настройки производительности и применения различных инструментов сбора информации, которая будет использоваться в течение процесса настройки. Заметим, что в данном разделе приведены примеры, которые вовсе необязательно часто встречаются на практике. Суть этих примеров - развить понимание того, как использовать различные инструментальные средства и методики, рассмотренные в этом цикле статей, для обнаружения и исправления проблем с производительностью.

Пример 1. Большое время отклика приложения

Суть проблемы заключалась в том, что время отклика Java-приложения было слишком большим. Используя topas, а затем vmstat, было установлено, что Java-приложение потребляло почти все ресурсы CPU. У функций, выведенных при помощи tprof, имелись некоторые проблемы, связанные со сборщиком мусора (например, localMark, которая использовалась в фазе Mark), что, в свою очередь, свидетельствует о возможных проблемах c размером Java-кучи.

Журналы GC подтвердили догадку о том, что куча разрасталась в большинстве случаев. Это обстоятельство, вкупе с многократными провалами распределения страниц и почти переполненной кучей, привело к тому, что Java-приложение тратило много времени на поиск свободной страницы, не находило ее, расширяло кучу и, в конце концов, удовлетворяло только один текущий запрос на предоставление страницы.

Данная проблема решается путем установления большего значения для -Xmine, что принуждает кучу быстрее увеличивать свой размер (см. совет MEM003 в статье 3). Таким образом, благодаря однократному увеличению размера кучи удается избежать возможных ошибок при распределении страниц.

Первый шаг, сделанный при помощи инструментов AIX, показал, что проблема связана с Java. Второй шаг был сделан исходя из того, что дальнейшее исследование показало более точную причину проблемы - GC, после чего усилия были сконцентрирован на журналах GC. На третьем шаге использовались доступные параметры настройки для прерывания странного цикла выполнения, по которому стало работать приложение, увеличив тем самым время отклика CPU.

Пример 2. Исправление JVMPI

Другой интересный сценарий - проблема с производительностью, при которой CPU был загружен большую часть времени. Команда verbosegc показала, что цикл сбора мусора GC вызывался слишком часто, и приложение большую часть своего времени выполняло сбор мусора.

Трассировочные данные verbosegc показали, что большая часть работы GC была вызвана большим числом распределений очень больших объектов (примерно по 10 MБ, а может быть, даже больше). Из-за этих распределений куча фрагментировалась, и выполнение циклов сбора мусора (GC cycles) длилось дольше, что, конечно же, влияло на производительность. Но на основе информации из verbosegc клиент не мог сказать, что за объекты в ней указаны.

Самый легкий способ распознать проблему состоял в том, чтобы проанализировать дамп кучи (heapdump) утилитой HeapRoots. Но здесь возникал другой вопрос: большие объекты не переживали цикл сбора мусора. Поэтому в heapdump и не было никаких данных об объектах подобного размера.

Данный случай является классическим примером пользы анализа журналов для поиска и исправления проблем в исходных кодах приложения. Java Virtual Machine Profile Interface позволяет легко решать подобные проблемы. В этом примере использовался один из вариантов метода, описанного в Using JVMPI to Identify Large Memory Allocations; благодаря этому методу удалось быстро найти исходный код, который производит неэффективное распределение памяти.

Пример 3. Неограниченный рост

В последнем примере этой статьи рассмотрен сценарий, который выглядит как простая проблема с изменением размера. Была сделана попытка выполнить масштабирование приложения до 1000 пользователей, и у приложения закончилось пространство в Java-куче. Вычисленный размер кучи, согласно числу пользователей, показал, что размер памяти нужно увеличить с 1 до 1,5 ГБ.

Но Java-куча не являлась причиной возникновения ошибки нехватки памяти. Java-куча имела необходимое количество свободной памяти, но в логах приложения было указано, что произошла ошибка из-за недостатка памяти. Команда svmon показала, что платформенно-зависимой кучей используется только четыре сегмента или 1 ГБ памяти, и четвертый сегмент практически пуст (см. раздел Balancing Memory в статье Getting more memory in AIX for your Java applications).

Для дальнейших исследований к команде svmon была добавлена опция -verbose:jni. Полученная таким образом дополнительная информация показала, что глобальный ссылочный пул JNI опустошен, что очень редко случается. Размер глобального ссылочного пула JNI настолько велик, что большинству нормальных приложений даже близко не удается подойти к его исчерпанию.

Сначала пробовали работать с проблемой путем увеличения числа ссылок JNI (чем выше -Xoss, тем больше JNI-пул). Но это действие только отсрочило неизбежное. И серьезная фрагментация Java-кучи, вызванная интенсивным использованием JNI-ссылок, также ни к чему не привела.

Истинная причина проблемы стала ясна после глубокого анализа архитектуры приложения: приложение создавало неограниченное число потоков. В ходе тестов было зафиксировано, что потоки будут ожидать выполнения методов-завершителей (finalizers), а поскольку поведение завершителей непредсказуемо, большое число этих потоков ждали освобождения своих JNI-ссылок. Решение двух описанных проблем одно - изменить код программы. В программный код были внесены следующие изменения: потоки были перемещены в пул потоков, завершители были заменены там, где это возможно, размеры кучи были четко определены.

Этот случай показывает, что иногда причина проблемы может быть скрыта гораздо глубже в приложении. Проблема с опустошением Java-кучи стала проблемой архитектуры приложения. Баланс между Java-кучей и системной динамической памятью является важной частью настройки производительности, но в данном случае только этого было недостаточно. Рассмотренные нами инструменты и методики позволяют создавать полную картину проблемы, которой можно воспользоваться при обосновании необходимости тех или иных настроек.


Заключение

Данная статья завершает цикл. Мы надеемся, что наш цикл статей поможет максимизировать производительность Java-приложений на AIX.

Авторы статей данного цикла благодарят Ашока Амбати (Ashok Ambati), Райеш Йеупаул (Rajesh Jeyapaul), Шарад Баллал (Sharad Ballal), Роджера Леуки (Roger Leuckie) и Марка Блуемела (Mark Bluemel) за их вклад и советы, которые помогли подготовить этот цикл статей. Отдельная благодарность Джону Тешу (John Tesch), чья подборка информации об AIX Java служила главным источником вдохновения при написании этого цикла.

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=431559
ArticleTitle=Оптимизация производительности Java в AIX: Часть 5. Ссылки и заключение
publish-date=09292009