
Несколько пользователей запускают приложения Java на 60-ядерном вычислительном сервере (на базе Linux/Ubuntu). Существуют различные приложения, и большинство из них не разрабатываются внутри компании.
Хотя системный администратор считает нормальным, чтобы Java-процесс конкретного пользователя использовал 10 ядер в любой момент времени, он хотел бы, чтобы они не использовали более 10.
Есть ли какая-либо конфигурация Java или ОС, которую можно использовать для предотвращения неограниченного захвата вычислительных ресурсов процессом?
решение1
Что касается ОС:
Я бы сказал, что классический метод — это установить привязку к ЦП с помощью
taskset
.Лучшей альтернативой является использование
cgroups
.И модное решение — запускать ваши приложения вДокерконтейнеры. Однако до Java 8 JVM не могла понять ограничения, накладываемые Docker (доступно только после 8u131+ бэкпортировано, не уверен, доступно ли это как экспериментальное в Java9 для части ЦП, но это для памяти, и полностью доступно в Java10)
решение2
Я бы сказал, что стоит посмотреть это видео.https://vimeo.com/181900266
В нем дается очень хороший обзор различий между Java, cgroups и контейнерами, а также того, как JVM определяет, например, количество процессоров.
Исходя из этого, я бы сказал, что вплоть до Java 8 JVM определяет количество доступных ЦП на пути, что она всегда считает, что все "онлайн" ЦП доступны для нее, потому что она использует sysconf(_SC_NPROCESSORS_ONLN) для этой цели. Даже если она cgroup'd или помещена в контейнер.
Начиная с Java 9 JVM будет использовать sched_getaffinity(), и это поможет, если cpuset используется для управления количеством ЦП для JVM. То есть JVM будет видеть только настроенные ЦП. Например, если использовать опцию Docker cpuset-cpus, то это действительно создаст ограничение для JVM. Примечание! Если cpushare настроен для JVM, это все равно не дает решения проблемы. JVM все равно будет видеть все ЦП в системе (независимо от того, находится ли он в контейнере), если настроен только cpushare.
решение3
Другая альтернатива в дополнение к тому, что уже упоминали другие (cgroup quota, cgroup cpuset) заключается в том, что вы можете явно указать Java, сколько процессоров она должна сообщать, когда библиотеки запрашивают, указав значение для параметра -XX:ActiveProcessorCount
. Любые библиотеки, которые автоматически выбирают количество потоков на основе значения Runtime.getRuntime().availableProcessors()
(например, Reactor's Schedulers.parallel()
), будут настраивать себя соответствующим образом. Это также может информировать об автоматической настройке Garbage Collector.