Java (до обновления 131 JDK8) приложения, работающие в контейнере докеров, проблемы с ЦП / памятью?

JVM (JDK 8 до обновления 131), запущенная в контейнерах докеров, игнорировала ограничения CGroup, установленные средой контейнера. И они запрашивали ресурсы хоста, а не то, что было выделено для контейнера. Результат является катастрофическим для JVM, т. Е. Поскольку JVM пыталась выделить себе больше ресурсов (ЦП или памяти), чем разрешено ограничениями CGroup, демон докера заметил бы это и убил бы процесс JVM или сам контейнер, если бы java-программа была работает с pid 1.

Решение проблемы с памятью - (возможно, исправлено в обновлении 131 JDK 8). Как описано выше, JVM выделяла себе больше памяти, чем разрешено для контейнера. Это можно легко исправить с помощью

  1. явная установка максимального предела памяти кучи (с использованием -Xmx) при запуске JVM. (до обновления 131)
  2. или передавая эти флаги - (после 131 обновления)
    -XX:+UnlockExperimentalVMOptions и
    -XX:+UseCGroupMemoryLimitForHeap

Устранение проблемы с процессором (возможно, исправлено в обновлении JDK 212). И снова, как описано выше, JVM, работающая в докере, будет напрямую смотреть на аппаратное обеспечение хоста и получать общее количество доступных процессоров. Затем он попытается получить доступ или выполнить оптимизацию на основе этих подсчетов ЦП.

  1. После обновления 212 JDK 8 любая JVM, работающая в контейнере докеров, будет соблюдать ограничения ЦП, выделенные для контейнера, и не будет напрямую смотреть в ЦП хоста. Если контейнер с ограничением ЦП запускается, как показано ниже, JVM будет соблюдать это ограничение и ограничится 1 ЦП.
    docker run -ti --cpus 1 -m 1G openjdk:8u212-jdk // jvms, запущенные в этом контейнере, ограничены 1 ЦП.
  2. ВОПРОС: Проблема с процессором, вероятно, исправлена ​​в обновлении 212 JDK8, но что, если я не могу обновить свою JVM и у меня установлена ​​версия до обновления 131, как я могу исправить проблема с процессором.

person Vamsh    schedule 08.10.2020    source источник
comment
Вы отметили это докером; должно быть очень просто обновить строку FROM в вашем образе и повторно запустить docker build для обновления JVM.   -  person David Maze    schedule 08.10.2020
comment
@DavidMaze, я ценю ваше решение. Но это не вариант. Я уже упоминал об этом как об одном из решений. Пожалуйста, перечитайте вопрос. Я знаю, что обновление до 212 в образе докера может исправить это. Но по внутренним причинам я не могу выйти за рамки обновления 131 и должен найти решение для JVM до 131. Это вопрос.   -  person Vamsh    schedule 08.10.2020
comment
@DavidMaze, иначе говоря, я не могу коснуться / изменить изображение или версию jdk в докере. В лучшем случае я могу изменить CMD или ENTRYPOINT, т.е. передать аргументы jvm.   -  person Vamsh    schedule 08.10.2020


Ответы (1)


Поддержка контейнеров Linux впервые появилась в JDK 10, а затем была перенесена на 8u191, см. JDK-8146115 .

В более ранних версиях JVM было указано следующее количество доступных процессоров.

Я написал небольшую общую библиотеку proccount, которая заменяет как sysconf, так и sched_getaffinity. Таким образом, эту библиотеку можно использовать для установки нужного количества доступных процессоров во всех версиях JDK до 8u191.

Как это работает

  1. Сначала он читает cpu.cfs_quota_us и cpu.cfs_period_us, чтобы определить, запущен ли контейнер с опцией --cpus. Если оба выше нуля, количество процессоров оценивается как

    cpu.cfs_quota_us / cpu.cfs_period_us
    
  2. В противном случае он читает cpu.shares и оценивает количество доступных процессоров как

    cpu.shares / 1024
    

    Такой расчет ЦП аналогичен тому, как он фактически работает в современном JDK с поддержкой контейнеров.

  3. Библиотека определяет (переопределяет) функции sysconf и sched_getaffinity для возврата количества процессоров, полученных в (1) или (2).

Как скомпилировать

gcc -O2 -fPIC -shared -olibproccount.so proccount.c -ldl

Как использовать

LD_PRELOAD=/path/to/libproccount.so java <args>
person apangin    schedule 08.10.2020
comment
оцените подробное объяснение. Спасибо. Linux container support first appeared in JDK 10 and then ported to 8u191 - понял. (1) Но разве это не превосходит всю суть пространств имен и контрольных групп. (2) из ​​вики - cgroup namespace type has existed since March 2016 in Linux 4.6. Итак, в чем смысл этого нового пространства имен cgroup. Почему приложения, например, JVM, должны заботиться о добавлении поддержки контейнеров - движок докеров, то есть containerd, должен обеспечивать изоляцию по умолчанию. Немного сложно осмыслить это ???? - person Vamsh; 11.10.2020
comment
@RedwinD Он обеспечивает изоляцию, но не виртуализацию. - person apangin; 11.10.2020
comment
Ваш пост отвечает на мой вопрос. Спасибо. Но сама технология кажется непонятной или запутанной. - person Vamsh; 12.10.2020
comment
цитата из вики - OS-level virtualization is an operating system paradigm in which the kernel allows the existence of multiple **isolated** user space instances. - как вы сказали, здесь используется слово isolated, а не virtualisation. Так что согласен с вами в этом. Но сама статья посвящена - виртуализации на уровне ОС - person Vamsh; 12.10.2020
comment
далее - в той же статье говорится, A computer program running on an ordinary operating system can see all resources (connected devices, files and folders, network shares, CPU power, quantifiable hardware capabilities) of that computer. However, **programs running inside of a container can only see the container's contents and devices assigned to the container.** - просто хочу подтвердить, что это абстракция или виртуализация. - person Vamsh; 12.10.2020