Визначити ідеальний розмір пам’яті для запуску програми Java може бути дуже важко. Розуміння вимог до обсягу пам’яті програми є важливим для досягнення максимальної продуктивності за найнижчих операційних витрат.
The New Stack розповідає, як використовувати файли журналу збирача сміття (GC) для визначення необхідного розміру пам’яті для програми.
Завдяки середовищу виконання Java ми можемо покластися на GC, щоб очистити пам’ять, яка більше не використовується, і зберегти загальний обсяг якомога меншим.
Роблячи це, GC може вивести файл журналу із великою кількістю інформації, яка може допомогти знайти проблеми в коді та визначити правильні розміри для серверів або віртуальних середовищ.
Як перевірити свою програму?
Найскладнішою, але найважливішою частиною реального тестування ваших програм є повторюване моделювання навантаження, яке нагадує фактичне використання програми. Це важливий крок у розробленні та розгортанні програми, який вимагатиме співпраці між вашими розробниками й командами DevOps.
Є кілька важливих результатів такого тесту: визначення обсягу пам’яті, необхідного програмі, і тестування її максимальної пропускної здатності.
Вказівки для досягнення цієї мети:
- Не поспішайте. Коли Java-застосунок виконується, JVM перекомпільовує найбільш використовуваний байт-код (файли класів) у рідний код. Цей процес займає деякий час (відомий як час розігріву), тому вам потрібно зачекати, поки програма буде використовуватися достатньо довго із типовим навантаженням, яке ви очікуєте. Це означає, що весь код, який виконується, був викликаний навантаженням програми.
- Будьте обережні з локальними тестами. Деякі тести можна легко виконати на вашій машині, але пам’ятайте про навантаження самого тесту. Виконання навантажувального тесту на тій самій машині, на якій запущено програму, може спричинити перевантаження процесора та/або пам’яті, що погіршить продуктивність тестованої програми.
- Використовуйте тест у реальних умовах. Тест дійсний лише тоді, коли ви можете змоделювати очікуване навантаження в середовищі, подібному до вашої виробничої системи.
- Тестування у виробництві. Журнали GC мають мінімальний вплив на продуктивність вашої системи. У багатьох випадках це буде набагато простішим і дешевшим рішенням для отримання реальних результатів журналу порівняно із налаштуванням повного тестового середовища.
Експерименти зі Spring PetClinic
Ми використовували застосунок Spring PetClinic, щоб зібрати результати тестів для цієї статті. Джерела доступні на GitHub і містять тестовий сценарій JMeter.
Запуск тестової програми
Щоб застосувати цей підхід, отримайте вихідний код, скомпілюйте програму та запустіть її за допомогою таких команд:
# Get the sources | |
$ git clone https://github.com/spring-projects/spring-petclinic | |
$ cd spring-petclinic | |
# Generate a JAR and run it. Use CTRL+C to stop the application | |
$ ./mvnw package | |
$ java -Xlog:gc,safepoint:gc.log::filecount=0 -jar target/*.jar |
Тепер вашу програму налаштовано на зберігання журналу збирання сміття в одному файлі.
Цей параметр ідеально підходить для цього тесту. Але коли вмикається журнал GC у виробництві, вам слід використовувати файли, що змінюються, щоб файл не став занадто великим і не заповнював простір для зберігання. Наприклад, використовуйте:
-Xlog:gc,safepoint:gc.log::filecount=10,filesize=100M
, щоб налаштувати ротацію журналу на максимум 10 файлів по 100 МБ кожен.
Якщо ви не визначаєте кількість і розмір файлу, за замовчуванням буде 5 файлів по 20 МБ кожен, тому журнал GC не використовуватиме понад 100 МБ.
Про JMeter
Проєкт Spring PetClinic містить тест JMeter. Цей тест можна виконати за допомогою Apache JMeter — програми Java зі 100% відкритим вихідним кодом, призначеної для завантаження тестової функціональної поведінки та вимірювання продуктивності.
Спочатку він був розроблений для тестування вебзастосунків, але згодом розширився до інших тестових функцій. Перевірте останню версію на цьому сайті та завантажте її.
$ cd ~/Downloads | |
$ wget https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.6.3.zip | |
$ unzip apache-jmeter-5.6.3.zip | |
$ rm apache-jmeter-5.6.3.zip |
Тести JMeter можна виконувати за допомогою програми графічного інтерфейсу користувача. Однак це не рекомендується, оскільки створює ризик впливу графічного інтерфейсу користувача на продуктивність тесту.
GUI слід використовувати лише для створення тесту або його запуску для перевірки конфігурації.
Створення тесту за допомогою JMeter GUI
Запустіть програму Apache JMeter GUI:
$ java -jar ~/Downloads/apache-jmeter-5.6.3/bin/ApacheJMeter.jar
- В інтерфейсі користувача натисніть «Файл» > «Відкрити» та виберіть файл
spring-petclinic/src/test/jmeter/petclinic_test_plan.jmx
. - Ви можете виконати тест для перевірки конфігурації, натиснувши кнопку «Пуск», яка запустить потоки для імітації 500 користувачів.
- Дайте йому працювати, поки тест не закінчиться. Кількість активних потоків зменшиться із 500 до 0.
Виконання навантажувального тесту із JMeter у Headless Mode
Для фактичного тесту ми запустимо JMeter у Headless Mode.
Після запуску тесту давайте створимо звіт із такими параметрами:
- -n : запускати в Headless Mode (без GUI).
- -t : шлях до
.jmx
тестового сценарію, який буде виконано. - -l : шлях до
.jtl
файлу для зберігання необроблених результатів. - -o : шлях до вихідної папки для створення інформаційної панелі звіту після навантажувального тесту, який має бути порожнім каталогом.
- -e : створити інформаційну панель звіту після навантажувального тесту.
$ java -jar ApacheJMeter.jar -n -t spring-petclinic/src/test/jmeter/petclinic_test_plan.jmx -l jmeter.jtl -o jmeter-report/ -e
Якщо ви не додасте параметр -e, то все одно зможете створити звіт HTML пізніше на основі .jtl
файлу, створеного під час тестового запуску.
- -g : шлях до
.jtl
файлу, створеного під час тесту. - -o : папка для зберігання звіту HTML.
$ java -jar ApacheJMeter.jar -g jmeter.jtl -o jmeter-report/
Оскільки кожна нова версія середовища виконання Java покращує продуктивність, важливо знати, яка версія використовується у вашій робочій системі. У прикладі наведені тести з Azul Zulu Builds OpenJDK, версія 21.0.3.
$ java -version | |
#openjdk version "21.0.3" 2024-04-16 LTS | |
#OpenJDK Runtime Environment Zulu21.34+19-CA (build 21.0.3+9-LTS) | |
#OpenJDK 64-Bit Server VM Zulu21.34+19-CA (build 21.0.3+9-LTS, mixed mode, sharing) |
Читання звіту JMeter
У каталозі HTML-звітів JMeter jmeter-report/
ви можете знайти вебсторінку із результатами тесту JMeter.
Тут ви не знайдете жодної інформації, пов’язаної з пам’яттю, а тільки результати тестів, визначених у тестовому файлі JMeter. Наприклад: процентиль часу відповіді, пропускну здатність у зверненнях за секунду тощо.
Перевірка результатів журналу GC
Цей gc.log
файл є тим місцем, де можна дізнатися більше про використання пам’яті нашою програмою.
За допомогою Azul GC Log Analyzer ми можемо прочитати цей файл і візуалізувати набір графіків у часі (настінний годинник і час роботи), щоб перевірити збирач сміття, компілятор JIT, системні показники тощо.
Наступні діаграми показують, що тривалість паузи збирача сміття залишається меншою за 10 мс після початкового завантаження, а розмір купи після збирання сміття залишається приблизно 64 МБ.
Ми рекомендуємо використовувати подвійне значення для вимірювання розмірів вашої системи. Таким чином, у цьому випадку програма зможе обробляти таке ж навантаження, як і під час тесту, зі 128 МБ пам’яті.
Ви можете дотримуватися того самого принципу у своїй програмі та повторно перевірити тривалість паузи й використання купи після зміни –Xmx
налаштувань середовища виконання Java або конфігурації пам’яті вашого віртуального середовища.
Відмінності в журналах GC між Azul Zing і Zulu збірками OpenJDK
За допомогою іншого внутрішнього тесту ми створили кілька додаткових файлів журналу, щоб продемонструвати різні результати, надані версією 17 Azul Zulu та Zing Builds OpenJDK.
Результати із Zulu
Коли ми створюємо журнал GC за допомогою Zulu збірки OpenJDK, то отримуємо ті самі дані у файлі журналу, що й більшість інших дистрибутивів.
Наступні діаграми показують нам, що тривалість паузи збирача сміття залишається меншою за 80 мс, а використання купи після збирання сміття залишається приблизно 1 ГБ для довгоживучих об’єктів у старому поколінні та 2 ГБ у новому поколінні для тимчасових об’єктів.
У цьому випадку загальна сума -Xmx4G
є достатньою і фактично використовується, але зазвичай стандартною рекомендацією було б встановити -Xmx
подвійне спостережуване використання купи. Ось це було б -Xmx6G
.
Результати із Zing
Ми повторили той самий тест із Zing — альтернативним середовищем виконання Java, яке базується на OpenJDK, але має кращий компілятор JIT (Falcon) і додатковий збирач сміття (C4, Continuously Concurrent Compacting Collector).
Графіки виглядають дещо інакше через додаткову інформацію, яку надає C4 Garbage Collector.
Для одночасних GC більш важливим показником є одночасна тривалість, поки GC активний паралельно до програми. Це не призупиняє роботу програми, але споживає трохи процесорного часу.
100% не означає, що він споживає 100% усього процесорного часу, оскільки базові 100% — це загальна кількість потоків GC, яка менша за кількість ядер ЦП.
Але залишатися на 100% протягом тривалого часу слід уникати, збільшуючи розмір купи. Більшість цього часу зазвичай витрачається GC на обробку тимчасових об’єктів.
У цьому випадку продуктивність програми була кращою із Zing порівняно із Zulu з тим самим -Xmx4G
.
Для загального визначення розміру графік Live Set для Zing також важливий, оскільки показує кількість живих об’єктів. Наприклад, без об’єктів, на які не посилаються, також відомих як сміття.
Журнал збирача сміття надає правильні показники, щоб перевірити, скільки пам’яті потрібно програмі. Дуже важливо мати змогу тестувати програму в тому самому середовищі й із таким же навантаженням, як і робоча система.
Нагадуємо, що слід бути готовими до нових змін у ліцензуванні Java.
Підписуйтеся на ProIT у Telegram, щоб не пропустити жодної публікації!