Привет, Хабр! Меня зовут Максим Шишкин, я инженер по нагрузочному тестированию в команде Platform V Works::Artifactory в СберТехе. Наше решение — менеджер репозиториев артефактов и контейнеров. Он позволяет организовать хранение, описание, тегирование сборок и дистрибутивов программных продуктов, а также готовых Docker-контейнеров.

В этой статье я расскажу, как и почему мы перешли на Java 17, как протестировали возможности нового сборщика мусора Z Garbage Collector и в результате сэкономили ресурсы виртуальных машин — а вместе с этим и финансы. Надеюсь, наш опыт будет полезен инженерам по сопровождению, командам разработки и тестирования.


Любая команда рано или поздно сталкивается с вопросом: как рационально использовать ресурсы стендов? В процессе развития команды получают несколько стендов для своих задач. Чаще всего проблем с утилизацией стендов ПСИ (приёмо-сдаточные испытания), ИФТ (интеграционно-функциональное тестирование), ДЕВ (разработка) не возникает. Но есть исключение — стенд НТ (нагрузочное тестирование).

Безусловно, стенд НТ должен быть максимально приближен к ПРОМу (промышленный стенд): это база. Но все прекрасно понимают, что при заказе больших ресурсов нужно будет и использовать их должным образом. А если использование недостаточное, может, лучше урезать ресурсы и сэкономить средства компании или перераспределить их?

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

В процессе нагрузочного тестирования мы решили улучшить наш продукт Platform V Works::Artifactory в рамках технического спринта. Желание понятное и вполне реализуемое.

В первую очередь решили перейти на более свежую версию Java, в нашем случае — с Java 11 на Java 17. Особенно нас заинтересовал новый Z Garbage Collector (ZGC) — масштабируемый сборщик мусора с низкой задержкой. В разных статьях приводились интересные числа по эффективности ZGC, но неизменным было одно: он значительно улучшал производительность тестируемых продуктов.

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

После перехода на Java 17 мы решили провести замеры и зафиксировать, так сказать, полученную прибыль. Но всё оказалось не так однозначно.

Мы сравнили с предыдущим сборщиком G1 GC (Garbage first Garbage Collector), который зарекомендовал себя самым лучшим образом. Для чистоты эксперимента замеряли на одной версии продукта Platform V Works::Artifactory 2.7.0, на одном стенде. Ресурсы во время тестирования никак не менялись, профиль нагрузки не изменялся и состоял из 38 операций. Результаты утилизации ресурсов представлены на рисунках ниже. КТС (комплекс технических средств) стенда НТ соответствует нашему сайзингу для 500 пользователей и приведён ниже.

Таблица 1. КТС стенда НТ:

Сервис

Тип

CPU (ядер)

RAM (Гб)

1

Artifactory

ВМ

16

32

2

NFS (Network File System)

ВМ

2

4

3

DB (Database)

ВМ

4

8

Утилизация Artifactory на Java 11 c G1 GC. Длительность теста 21 час.
Утилизация Artifactory на Java 11 c G1 GC. Длительность теста 21 час.
Утилизация Artifactory на Java 17 c ZGC. Длительность теста 72 часа.
Утилизация Artifactory на Java 17 c ZGC. Длительность теста 72 часа.

На первый взгляд, ничего не поменялось, кроме использования памяти. При использовании Java 17 c ZGC резервируется около 4 Гб ОЗУ (RAM), а всё остальное практически целиком используется под кеш. В результате мы решили уменьшить ОЗУ на сервере Artifactory в два раза, до 16 Гб, и проверить работоспособность продукта при таком значении. Но об этом чуть ниже, а пока зафиксируем показатели по всем операциям и сравним их между собой.

Таблица 2. Результаты тестов надёжности по каждой операции:

Наименование операций

Надёжность

Разница в процентах

Java 11 G1 GC

Java 17 ZGC

RPS

95 %

99 %

RPS

95 %

99 %

95 %

99 %

0

Всего

3340

212

407

3350

184

245

-14

-40

1

Maven

2273

42.0

111

2309

17.2

55.1

-59

-50

2

NPM

659

90.3

197

669

27.3

82.4

-70

-58

3

Nuget

65.9

46.5

632

66.9

19.1

115

-59

-82

4

PYPI

49.4

42.9

632

50.2

16.8

110

-61

-83

5

RAW

16.5

41.0

633

16.7

16.1

89.8

-61

-86

6

YUM

6.59

35.5

429

6.69

14.4

69.9

-59

-84

7

Search

224

84.7

294

228

41.8

106

-51

-64

8

Content selectors

0.381

20.3

53.8

0.397

8.24

20.2

-59

-62

9

Privileges

0.392

74.1

202

0.400

23.3

61.5

-69

-70

10

Roles

0.381

2290

5030

0.392

1840

2340

-20

-53

11

0.381

106

189

0.389

102

184

-4

-3

12

Users

0.392

2170

2640

0.389

2140

2380

-1

-10

13

0.392

776

975

0.389

837

1080

+8

+11

14

/repositorySettings

0.317

45.0

93.0

0.297

13.2

34.5

-71

-63

15

/repositories

0.325

32.9

61.9

0.306

12.7

28.3

-61

-54

16

/blobstores

0.325

258

355

0.314

242

305

-6

-14

17

/email

0.314

18.9

51.7

0.311

7.75

18.7

-59

-64

18

/featureFlags

0.314

18.1

44.6

0.311

5.07

15.7

-72

-65

19

/formats/upload-specs

0.297

18.4

37.2

0.319

4.85

14.5

-74

-61

20

/lifecycle/phase

0.311

18.0

45.0

0.311

4.79

14.7

-73

-67

21

/read-only

0.311

20.9

64.8

0.311

8.96

19.5

-57

-70

22

/routing-rules

0.306

20.6

43.2

0.319

9.61

21.2

-53

-51

23

/script

0.306

20.9

49.2

0.311

9.36

20.0

-55

-59

24

/security/user-sources

0.311

18.8

44.8

0.314

7.80

18.4

-59

-59

25

/security/anonymous

0.314

18.9

42.5

0.311

7.77

18.1

-59

-57

26

/security/realms/active

0.319

19.0

53.2

0.311

7.80

19.1

-59

-64

27

/security/realms/available

0.311

20.9

52.9

0.317

9.82

21.5

-53

-59

28

/security/ssl/truststore

0.308

18.5

39.5

0.311

7.68

18.4

-58

-53

29

/status

0.311

18.9

43.5

0.317

6.13

15.3

-68

-65

30

/status/check

0.319

643

801

0.314

625

735

-3

-8

31

/status/writable

0.311

18.8

45.4

0.317

6.28

16.0

-67

-65

32

/system/node

0.311

19.1

41.2

0.314

7.67

17.9

-60

-57

33

/tasks

0.303

61.7

107

0.314

49.4

76.9

-20

-28

34

/rapture_State_get

0.306

757

863

0.300

786

885

+4

+3

35

/nexus

0.314

20.0

51.3

0.303

6.66

16.3

-67

-68

36

/swagger.json

0.311

140

325

0.303

33.4

88.7

-76

-73

37

/login

0.0139

10.9

55

0.0222

6.71

102

-38

+85

38

/logout

0.0139

6.40

40

0.0222

2.82

81

-56

+103

Результаты получились впечатляющие. Улучшение времени отклика зафиксировано практически по всем операциям. 95 % и 99 % — это, соответственно, 95-й и 99-й перцентили времени отклика, выраженные в миллисекундах (мс).  

К важным операциям можно отнести операции с репозиториями (с 1 по 6) и поиск (7 операция). В нашем случае все они получили хороший прирост. Где‑то прирост составил 51 % (операции c репозиторием Maven), а где‑то — целых 86 % (операции c репозиторием RAW).

Показатели нескольких операций (а именно четырёх) не улучшились, а даже наоборот. К примеру, худший результат — это увеличение времени отклика в два раза (или на 103 %, 38 операция). Увеличение с 40 мс до 81 мс, в целом, для нас не критично, как и с 37 операцией. А вот 13 и 34 операции мы взяли на доработку. После этого нас заинтересовало изменение в утилизации памяти, и вот об этом поподробнее.

Мы и раньше исследовали продукт на разных КТС, увеличивали и уменьшали значения ЦПУ (CPU) и ОЗУ. Но в конечном счёте пришли к тому, что самая работоспособная версия, которая соответствует всем требованиям и критериям, — это именно версия на 16 ядер ЦПУ и 32 Гб ОЗУ.

И вот тут для нас Java 17 c ZGC заиграла новыми красками. КТС стенда НТ изменился, уменьшилось ОЗУ до 16 Гб только на сервере Artifactory.

Таблица 3. КТС стенда НТ:

Сервис

Тип

CPU (ядер)

RAM (Гб)

1

ARR

ВМ

16

16

2

NFS

ВМ

2

4

3

DB

ВМ

4

8

В результате проведённого на этих ресурсах НТ с использованием Java 17 c ZGC удалось подтвердить работоспособность и надёжность конфигурации. Этот КТС стал новым сайзингом для 500 пользователей. Данные по утилизации ресурсов во время тестов приведены ниже.

Поиск максимальной производительности Artifactory. Длительность теста 1 час 20 минут.
Поиск максимальной производительности Artifactory. Длительность теста 1 час 20 минут.
Подтверждение максимальной производительности Artifactory. Длительность теста 1 час 20 минут.
Подтверждение максимальной производительности Artifactory. Длительность теста 1 час 20 минут.
Надёжность Artifactory. Длительность теста 24 часа.
Надёжность Artifactory. Длительность теста 24 часа.

Рисунки и результаты конкретного продукта — это, конечно, хорошо. Но их необходимо сравнить не только между собой, но и с конкурентами на рынке. В качестве конкурента выступит Sonatype Nexus Repository.

Для сравнения с результатами нашего продукта я взял две конфигурации (Medium и Large) из документации Nexus Repository. С точки зрения ресурсов Platform V Works::Artifactory с сайзингом для 500 пользователей, который мы и тестируем на стенде НТ, находится практически между ними.

Sonatype Nexus Repository Architecture 2 (Medium Profile Size) состоит из одного сервера (Node) c двумя ядрами CPU и 8 Гб RAM. Architecture 3 (Large Profile Size) состоит из трёх серверов. Суммарно для такой архитектуры нужно 12 ядер CPU и 48 Гб RAM. Напомню, что для нашей версии нужно 16 CPU и 16 RAM.

Получается, что Artifactory необходимо чуть больше СPU, но при этом кратно меньше RAM. В документации продукта Sonatype Nexus Repository используются такие понятия, как RPH (количество запросов в час) и RPD (количество запросов в день). На основе этих данных рекомендуются соответствующие архитектуры (конфигурации). Профиля нагрузки в документации нет, есть только показатель за час (фактически тест подтверждения максимальной производительности) и за день (фактически тест надёжности).

Спомощью несложных математических расчётов вычисляем, что, исходя из документации Sonatype Nexus Repository, день длится 10 часов. Или же, если погрузиться в основы методики нагрузочного тестирования (МНТ), тест надёжности должен составлять около 70-80% интенсивности нагрузки теста подтверждения максимальной производительности. Таким образом, если взять величину 80 %, то получается, что день длится 12,5 часов.

Мы проводим тесты надёжности длительностью сутки или более. Конечно же, бывают исключения, тем не менее, надёжность подтверждается на нагрузке в 24 часа. Но для простоты подсчёта и сравнения тоже возьмём 10 часов.

Безусловно, нужно понимать, что без информации о профиле нагрузки качественного сравнения не получится. Но оценить по тем параметрам, которые у нас есть и доступны в документации, можно и даже нужно. Сравнение — в таблице ниже.

Таблица 4. Сравнение с Sonatype Nexus Repository:

Характеристика

Sonatype Nexus Repository Architecture 2 (Medium)

Platform V Works::Artifactory

Sonatype Nexus Repository Architecture 3 (Large)

1

Node

1

1

3

2

CPU, ядер

2

16

4 (4х3=12)

3

RAM, Гб

8

16

16 (16х3=48)

4

RPH, запросов в час

100 000

1 260 000

1 000 000

5

RPD, запросов в день

1 000 000

12 600 000

10 000 000

Даже если стоимость эксплуатации была бы одинаковой (4 ядра CPU у Artifactory по стоимости эксплуатации были бы равны 32 Гб RAM у Sonatype Nexus Repository Architecture 3 (Large)), можно сказать, что использование Java 17 и ZGC позволило нашему продукту показать более высокую эффективность и производительность. В данном случае разница в сопоставлении с Sonatype составляет 26 %.

Заключение

Пора подводить итоги, они зафиксированы в таблице ниже. С одной стороны, ZGC и Java 17 приятно удивили своей производительностью в целом и утилизацией ОЗУ в частности. Но неожиданно удивило и потребление ЦПУ. В нашем случае потребление выросло на 20 %. Это не самый приятный момент, особенно в условиях ограниченности ресурсов.

Характеристика

Java 11 G1 GC

Java 17 ZGC

Разница

1

Утилизация CPU (ЦПУ), %

40

50

+20%

2

Утилизация RAM (ОЗУ), Гб

14

4

-71%

3

Время отклика 95%, усреднённое по всем операциям

212

184

-14%

4

Время отклика 99%, усреднённое по всем операциям

407

245

-40%

Хотя, если посмотреть на ситуацию иначе, на стенд НТ было выделено 16 ядер CPU, и это значение осталось неизменным. А значит, стоимость эксплуатации в этом компоненте для нас не изменилась, в отличие от RAM. По результатам данного исследования, RAM уменьшилась в два раза (на 16 Гб) без негативного эффекта — и это хороший результат и экономия, заложенная в будущую эксплуатацию продукта.

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

Комментарии (2)


  1. sparhawk
    03.12.2025 12:05

    Интересно, как поменялось среднее и медианное время отклика


  1. ris58h
    03.12.2025 12:05

    Утилизация CPU (ЦПУ), % | 40 | 50 | +20%

    Как получилось +20? Почему не +25?