Недавно я снова провел некоторое исследование и наткнулся на это. Прежде чем плакать об этом команде OpenJDK, я хотел посмотреть, наблюдал ли кто-то еще или не согласен с моими выводами.
Итак, широко известно, что JVM долгое время игнорировал ограничения памяти, применяемые к контрольная группа. Почти так же широко известно, что теперь он учитывает их, начиная с Java 8, обновляя что-то и 9 и выше. К сожалению, вычисления, сделанные на основе ограничений cgroup, настолько бесполезны, что вам все равно придется делать все вручную. См. Google и сотни статей по этому вопросу.
Что я обнаружил всего за несколько дней go и не читал ни в одной из этих статей, так это то, как JVM проверяет число процессоров в cgroups. Количество процессоров используется для определения количества потоков, используемых для различных задач, включая сборку мусора. Поэтому очень важно получить его правильно.
В группе (насколько я понимаю, и я не эксперт) вы можете установить ограничение на доступное время процессора (параметр --cpus
Docker). Это ограничивает только время, а не параллельность. Существуют также доли процессора (параметр --cpu-shares
Docker), которые представляют собой относительный вес для распределения времени процессора под нагрузкой. Docker устанавливает значение по умолчанию 1024, но это чисто относительный масштаб.
Наконец, существуют наборы процессоров (--cpuset-cpus
для Docker) для явного назначения cgroup, и такой контейнер Docker на подмножество процессоров. Это не зависит от других параметров и фактически влияет на параллелизм.
Итак, когда речь идет о проверке количества потоков, которые мой контейнер может выполнять параллельно, насколько я могу судить, релевантен только набор процессоров. , JVM, тем не менее, игнорирует это, вместо этого используя предел ЦП, если он установлен, в противном случае ЦП делится (предполагая, что значение по умолчанию 1024 является абсолютной шкалой). Это ИМХО уже очень неправильно. Он вычисляет доступное время процессора для определения размера пулов потоков.
В Кубернетах становится все хуже. Лучшая практика AFAIK - не устанавливать лимит ЦП, чтобы узлы кластера имели высокую загрузку. Кроме того, для большинства приложений следует установить низкий запрос ЦП, поскольку они будут простаивать большую часть времени, и вы хотите запланировать множество приложений на одном узле. Kubernetes устанавливает запрос в миллипроцессорах как долю процессора, которая, скорее всего, ниже 1000м. В этом случае JVM всегда использует один процессор, даже если ваш узел работает на каком-то 64-ядерном процессоре.
Кто-нибудь когда-нибудь также наблюдал это? Я что-то здесь упускаю? Или разработчики JVM на самом деле усугубили ситуацию при реализации ограничений cgroup для процессора?
Для справки: