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

Но, есть одно «но»: наша CRM — SalesMax — написана на java, а, следовательно, периодически возникают паузы, связанных с работой сборщика мусора. До последнего времени, это было тем неизбежным злом, с которым нужно было просто смириться.

И вот, Oracle анонсировали новый сборщик мусора — ZGC. По предварительным анонсам, он должен был решить проблему подвисаний java приложений — заявленные паузы не должны превышать 100 мс даже на многогигабайтных кучах. С нашими 6Гб максимального использования памяти, все, и подавно, должно быть хорошо.

Итак, приступим.

Добавляем в standalone.conf сервера приложений wildfly строчку

   JAVA_OPTS="$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UseZGC"

Запускаем систему, прогоняем нагрузочные тесты.

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

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

И вот, вечер субботы. Мы спокойно играем в бильярд, время за полночь. Звонок от менеджера: у клиента CRM не работает.

Проверяем — клиент с того самого сервера. Телефон в руки, открываю Termius, пытаюсь подключиться к серверу по ssh — тишина… Еле-еле, спустя секунд 20, которые в тот момент показались вечностью, но зайти все же удалось. И что же мы видим? Несмотря на установленные в параметрах запуска ограничения -Xmx6144M, процесс java израсходовал всю доступную память. Спустя какое-то время, система и вовсе данный процесс убила.

Так что, использование ZGC пришлось отключить. Работа CRM системы сразу пришла в норму. Казалось бы — делать нечего, будем ждать, пока в Oracle все допилят.

Но, спустя некоторое время, на глаза попалась статья в которой автор делился положительным опытом использования другого сборщика мусора — Shenandoah, разработчик которого преследовал ровно те же самые цели, а именно: сокращение времени, которое в сборщике мусора занимает фаза «stop the world».

Мы решили: почему бы и нет?

Найдя страницу, с которой можно скачать предварительно скомпилированный JDK — https://builds.shipilev.net/, мы приступили к тестированию: добавляем в standalone.conf новые ключи:

   JAVA_OPTS="$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC"

На этот раз, тестирование показало, что все, в общем-то, ОК. И паузы на сборку мусора сократились, и, что самое приятное — непредсказуемый рост расхода памяти прекратился. В продакшене все работает просто идеально.

Какие можно сделать выводы? Я понимаю, что в Oracle тоже идет развитие, и те сложности, с которыми мы столкнулись в октябре 2019 года, возможно, уже исправлены, и ZGC вскоре можно будет дать второй шанс. Но на данный момент, лично мы остановили свой выбор на Shenandoah GC, и не пожалели.

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


  1. NikStrig
    27.11.2019 13:46

    В Java 13 починили. m.habr.com/ru/company/jugru/blog/467789


    1. maximwirt Автор
      27.11.2019 13:48

      Спасибо, будем иметь в виду. Пока у нас Java 11.


    1. apangin
      28.11.2019 15:19

      Что починили? Если вы про JEP 351, то эта фича вообще о другом.


  1. UbuRus
    27.11.2019 13:53

    В каком широко используемом docker image есть Shenandoah в составе OpenJDK 11? Докеры имени Ш. это конечно хорошо, но хочется чего-то протестированного


    1. vektory79
      27.11.2019 17:34

      Shenandoah попадает во все репы RHEL и их производных. В частности в CentOS (откуда мы и используем, правда пока только в тестировании) и Fedora.


      Так же этот GC попал в OpenJDK 12 на постоянной основе.


      P.S. И раз уж зашла о том речь, то в последнем апдейте Java в Shenandoah поправили важную регрессию, после исправления которой общее быстродействие стало почти на уровне G1 GC (До этого отличие было в десятки процентов): https://bugs.openjdk.java.net/browse/JDK-8232575
      P.P.S. В Java 8 с Шенандой не работает отладка. Виснет наглухо. Но есть обходные пути (которые, увы, неприменимы для нас): https://mail.openjdk.java.net/pipermail/shenandoah-dev/2019-October/010960.html


      1. UbuRus
        27.11.2019 17:48

        Shenandoah попадает во все репы RHEL и их производных. В частности в CentOS (откуда мы и используем, правда пока только в тестировании) и Fedora.

        Отлично, а готовый image на подобии https://hub.docker.com/_/amazoncorretto есть, чтобы не собирать руками, а взять оттестированный?


        Так же этот GC попал в OpenJDK 12 на постоянной основе.

        Это да, лучше бы в 11 попал, кто в прод 12-16 тянуть будет


        https://bugs.openjdk.java.net/browse/JDK-8232575

        Печальненько, видимо придется дальше тюнить G1 на low latency, пока не забекпортят в 11, или ждать 17


        1. vektory79
          27.11.2019 17:51

          Печальненько, видимо придется дальше тюнить G1 на low latency, пока не забекпортят в 11, или ждать 17

          Это-то как раз уже везде забекпортили. Включая 8.


          А с готовыми образами — не подскажу...


          1. UbuRus
            27.11.2019 17:55

            Это-то как раз уже везде забекпортили. Включая 8.

            Не вижу этого в тикете, в 11.0.6 ждать?


            1. vektory79
              27.11.2019 18:00

              Видимо забыли отметить… Информация о портировании поступила от разработчика Шенанды и судя по нашим тестам это так и есть.


              Фикс прилетел в 14, 11, 8.

              Как раз таки в 11.0.5 попало.


  1. time2rfc
    27.11.2019 14:28

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


  1. apangin
    28.11.2019 15:16

    Казалось бы — делать нечего, будем ждать, пока в Oracle все допилят
    Долго ждать бы пришлось… Как Oracle узнает, что у вас есть проблема с ZGC? Вы им репортили? И почему вы решили, что это бага в ZGC, а не в настройках/версии ОС?

    ZGC использует технику colored pointers и multi-mapping. Это значит, что один и тот же диапазон физической памяти отображается в несколько виртуальных диапазонов, из-за чего Linux криво считает RSS процесса. Так что очень вероятно, что это не «процесс java израсходовал всю доступную память», а вы его не так «приготовили».

    Статья называется «опыт использования», а по факту вижу: включили -> с первого раза не заработало -> выключили. И в чём тут опыт? Был бы интересен хоть какой-то минимальный анализ, что же пошло не так.


    1. maximwirt Автор
      28.11.2019 16:02

      По факту, некорректное поведение подтолкнуло к проведению исследований и поиску возможных утечек памяти. В общем-то можно сказать спасибо данной ситуации, кое-что в CRM было переделано, чтобы память расходовалась более экономно — 2 недели занимались только этим. Но ситуацию с проблемами при использовании ZGC это не решило. По поводу настроек ОС — у нас убунту и JDK изначально ставился через apt из официального репозитория, и ранее сложностей с утечками памяти не наблюдалось. В сухом остатке — подключение ZGC = outofmemory и последующее вмешательство oom killer-а, отключение = все ОК.


      1. Andrey0Lomakin
        29.11.2019 08:38
        +1

        maximwirt Мне кажеться Вы всё таки пропустили важный момент в комментарии. ZGC использует мультимаппинг. Там по моему 3 цвета замапленных на RSS если я не ошибаюсь. Т.е. Ваши 6Gb heap система видит как 18Gb heap и начинает использовать SWAP и в конце срабатывает OOM killer. Возможно Вм и правда надо отменить своппироание и убрать OOM killer. Хотя я и сам считаю что как раз мудтимаппинг и есть главная проблема ZGC, но она заложена в его архитектуре.