Вопрос или проблема
Я использую систему Linux, в которой много пользователей, но иногда происходят злоупотребления; когда пользователь запускает отдельный процесс, использующий более 80% CPU/памяти.
Существует ли способ предотвратить это, ограничив использование CPU процессом (например, до 10%)? Я знаю о cpulimit
, но, к сожалению, он применяет ограничение только к процессам, которые я указываю (например, к отдельным процессам). Поэтому мой вопрос заключается в том, как можно применить ограничение ко всем запущенным процессам и процессам, которые будут запущены в будущем, без необходимости указывать их ID/путь, например?
nice / renice
nice
— это отличный инструмент для ‘разовых’ настроек системы.
nice COMMAND
cpulimit
cpulimit
, если вам нужно запустить процесс с высокой нагрузкой на CPU, и наличие свободного времени CPU критично для отзывчивости системы.
cpulimit -l 50 -- COMMAND
cgroups
cgroups
применяет ограничения к набору процессов, а не только к одному.
cgcreate -g cpu:/cpulimited
cgset -r cpu.shares=512 cpulimited
cgexec -g cpu:cpulimited COMMAND_1
cgexec -g cpu:cpulimited COMMAND_2
cgexec -g cpu:cpulimited COMMAND_3
Ресурсы
http://blog.scoutapp.com/articles/2014/11/04/restricting-process-cpu-usage-using-nice-cpulimit-and-cgroups
http://manpages.ubuntu.com/manpages/xenial/man1/cpulimit.1.html
Хотя злоупотребление памятью может существовать, злоупотребление CPU не является проблемой: когда CPU бездействует, запущенный процесс (под “запущенным” я имею в виду, что процесс не ждет I/O или чего-то еще) будет по умолчанию занимать 100% времени CPU. И нет смысла вводить ограничение.
Теперь вы можете установить приоритеты благодаря nice
. Если вы хотите, чтобы они применялись ко всем процессам для данного пользователя, вам нужно убедиться, что оболочка входа пользователя запускается с nice
: дочерние процессы унаследуют значение nice
. Это зависит от того, как пользователи входят в систему. Например, смотрите Приоритизировать входы ssh (nice).
В качестве альтернативы вы можете настроить виртуальные машины. Установка ограничения на один процесс не имеет большого смысла, так как пользователь может запустить много процессов, злоупотребляя системой. С виртуальной машиной все ограничения будут глобальными для виртуальной машины.
Еще одно решение — установить ограничения в /etc/security/limits.conf
; смотрите man-страницу limits.conf(5). Например, вы можете установить максимальное время CPU на вход и/или максимальное количество процессов на вход. Вы также можете установить maxlogins
на 1 для каждого пользователя.
Вы смотрели cgroups? Есть информация на Arch Wiki. Посмотрите раздел о cpu.shares
, похоже, что это то, что вам нужно, и они могут работать на уровне пользователя, так что вы можете ограничить все процессы пользователя сразу.
Для памяти то, что вам нужно, это ulimit -v
. Обратите внимание, что ulimit
наследуется дочерними процессами, поэтому, если вы примените его к оболочке входа пользователя в момент входа, он применится ко всем его процессам.
Если ваши пользователи все используют bash
в качестве оболочки входа, добавление следующей строки в /etc/profile
должно установить жесткое ограничение в 1 гигабайт (точнее, один миллион килобайтов) для всех процессов пользователя:
ulimit -vH 1000000
Опция H
обеспечивает жесткое ограничение, то есть пользователь не сможет его изменить позже. Конечно, пользователь все равно может заполнить память, запустив достаточно много процессов одновременно.
Для других оболочек вам нужно будет выяснить, какие файлы инициализации они читают (и какую другую команду, кроме ulimit
, они используют).
Что касается CPU, то то, что вы хотите, не совсем имеет смысл. Какова пользы в том, чтобы оставлять 90% CPU неиспользуемым, когда работает только один процесс? Я думаю, что вам действительно нужен nice
(и, возможно, ionice
). Обратите внимание, что, как и в случае с ulimit
, значения nice
наследуются дочерними процессами, поэтому применения его к оболочке входа в момент входа будет достаточно. Я предполагаю, что это также относится к ionice
, но я не уверен.
Так как в ваших тегах есть centos
, вы можете использовать systemd
.
Например, если вы хотите ограничить пользователя с ID 1234
:
sudo systemctl edit --force user-1234.slice
Затем введите и сохраните это:
[Slice]
CPUQuota=10%
В следующий раз, когда этот пользователь войдет в систему, это окажет влияние.
Ман-пейджы: systemctl
, systemd.slice
, systemd.resource-control
…
Так как вы утверждаете, что cpulimit не является практичным в вашем случае, я предлагаю вам обратить внимание на nice, renice и taskset, которые могут быть близки к тому, что вы хотите достичь, хотя taskset позволяет установить привязанность процесса к CPU, так что это может быть не сразу полезно в вашем случае.
Если вы хотите ограничить уже запущенные процессы, вам придется делать это по одному по PID, но вы можете создать пакетный скрипт, позволяющий сделать это, как тот, который приведен ниже:
#!/bin/bash
LIMIT_PIDS=$(pgrep tesseract) # PIDs в очереди, замените tesseract на ваше имя
echo $LIMIT_PIDS
for i in $LIMIT_PIDS
do
cpulimit -p $i -l 10 -z & # до 10 процентов процессов
done
В моем случае pypdfocr
запускает ненасытный tesseract
.
Также в некоторых случаях, когда ваш CPU довольно хороший, вы можете просто использовать renice
следующим образом:
watch -n5 'pidof tesseract | xargs -L1 sudo renice +19'
Отказ от ответственности: этот ответ предназначен для тех, кто находит это полезным и хочет контролировать процессы, которые они запускают, и хотят ограничить использование CPU независимо от текущих нагрузок системы.
Я обнаружил, что на моем Linux Mint cpulimit
не помог. Однако работали два способа:
cputool
: например,cputool -c 10 -- stress -c 4
(stress
— это (на мой взгляд) небольшое полезное средство для тестирования нагрузки на систему)
Недостаток: нельзя так легко изменить использование после запуска.
cgroups
Код (удивительно, если я удаляю эту строку, форматирование кода ниже нарушается):
sudo cgcreate -g cpu:mygroup1
cat /sys/fs/cgroup/mygroup1/cpu.max # не обязательно, пытался найти причину ошибки и технические детали для справки
max 100000
sudo cgset -r cpu.max="200000 100000" mygroup1
sudo cgexec -g cpu:mygroup1 sudo -u username1 -g groupname1 stress -c 4
stress: info: [125425] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
Пользователь не может запустить процесс с помощью cgroups
, если не предоставляет права доступа, я пока не изучил, как добавить права (надеюсь, это возможно), но вместо этого использую sudo.
# в другом терминале, чтобы изменить использование (синтаксис изменяет только первое значение):
sudo cgset -r cpu.max=100000 mygroup1
Заметки для cgroups:
cpu.max
имеет два значения: первое значение — это разрешенная квота времени в микросекундах, в течение которой все процессы в дочерней группе могут работать в течение одного периода. Второе значение указывает длину периода. Для многопроцессорных систем первое значение — это квота для всех ядер, второе — для одного, так что установка первого значения в два раза больше второго ожидаемо приведет к использованию CPU, равному 2, деленному на общее количество ядер.
На моей системе минимальное допустимое значение — 1000, максимальное — 1000000.
Использование второго значения 100000 (по умолчанию) приводит к дополнительному снижению скорости в 2-3 раза, когда я запускаю ffmpeg
, использование 1000000 не приводит к заметному снижению.
Удивительно для меня — почему для процессоров GHz каждые сотни миллисекунд имеют такое значение, а каждые секунды — нет?
cgroups
могут использоваться без cgcreate
, cgset
, cgexec
(они находятся в пакете cgroup-tools
, который для дистрибутива Linux Mint требует дополнительной установки). На мой взгляд, хорошее описание того, как это сделать:
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications_managing-monitoring-and-updating-the-kernel, как запустить процесс в cgroup: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/starting_a_process.
Ответ или решение
Для ограничения использования CPU процессами в Linux можно использовать различные подходы, чтобы предотвратить чрезмерное потребление ресурсов одной программой. Вот несколько методов, которые позволят ограничить использование CPU до 10% как для уже запущенных процессов, так и для будущих.
1. Использование cgroups
Cgroups (Control Groups) — это мощный механизм, позволяющий ограничивать и управлять ресурсами на уровне групп процессов. Чтобы создать cgroup и установить ограничение на использование CPU, выполните следующие шаги:
-
Создание группы процессов:
sudo cgcreate -g cpu:/cpulimited
-
Установка лимита для этой группы:
Для установки лимита CPU на 10%, используем следующие команды:echo "10000 100000" | sudo tee /sys/fs/cgroup/cpu/cpulimited/cpu.max
Здесь первое значение (10000) — это квота в микросекундах, а второе (100000) — период в микросекундах, что соответствует 10% использования.
-
Запуск процессов в cgroup:
Для запуска процесса в созданной группе используйте:sudo cgexec -g cpu:cpulimited <COMMAND>
2. Настройка user.slice с помощью systemd
Если ваша система использует systemd, вы можете настроить лимиты для всех процессов определенного пользователя, редактируя его slice
:
-
Редактирование slice:
sudo systemctl edit --force user-<USER_ID>.slice
-
Добавление параметра:
В открывшемся редакторе добавьте следующие строки:[Slice] CPUQuota=10%
Это будет ограничивать использование CPU всеми процессами этого пользователя до 10%.
3. Использование ulimit
Применение команды ulimit
также может быть полезным для ограничения ресурсов. Например, чтобы установить лимит на использование CPU в более традиционном виде:
- Открытие файла конфигурации
/etc/security/limits.conf
:
Добавьте следующие строки, чтобы ограничить использование CPU для определенного пользователя:<username> hard cpu 60
Это будет ограничивать CPU для заданного пользователя (в секундах).
4. Использование nice
и renice
Программа nice
позволяет изменять приоритет процессов. Более низкий приоритет (более высокое значение nice) может помочь снизить использование CPU:
-
Запуск процесса с
nice
:nice -n 19 <COMMAND>
-
Изменение приоритета уже запущенного процесса:
renice 19 -p <PID>
5. Использование cpulimit
Хотя cpulimit
не является самым удобным для автоматизации, вы можете использовать его в скрипте для управления уже запущенными процессами:
#!/bin/bash
LIMIT_PIDS=$(pgrep <PROCESS_NAME>) # Замените <PROCESS_NAME> на необходимый процесс
for i in $LIMIT_PIDS; do
cpulimit -p $i -l 10 -z &
done
Заключение
Эти методы могут быть использованы индивидуально или в комплексе для ограничения использования CPU на вашем сервере Linux. Лучшим решением для управления процессами и ограничений является использование cgroups, так как он предоставляет наиболее гибкие и мощные возможности для управления ресурсами. Если у вас есть контроль над конфигурацией системы, использование systemd также упростит задачу.