Как ограничить общие ресурсы (память) процесса и его дочерних элементов

16

Существует множество вопросов и ответов об ограничении ресурсов одного процесса, например, RLIMIT_AS может использоваться для ограничения максимального объема памяти, выделяемой процессом, который можно рассматривать как VIRT в подобии top. Подробнее по теме, например здесь. Есть ли способ ограничить объем памяти, который конкретный процесс может использовать в Unix?

setrlimit(2) Документация гласит:

Дочерний процесс, созданный с помощью fork (2), наследует ограничения ресурсов своего родителя. Пределы ресурсов сохраняются в execve (2).

Это следует понимать следующим образом:

Если процесс имеет RLIMIT_AS, например, 2 ГБ, он не может выделить больше памяти, чем 2 ГБ. Когда он порождает дочерний элемент, ограничение адресного пространства в 2 ГБ будет передано дочернему элементу, но отсчет начинается с 0. 2 процесса вместе могут занимать до 4 ГБ памяти.

Но что может быть полезным для ограничения общего объема памяти, выделенной целым деревом процессов?

JPE
источник
Сопутствующий: unix.stackexchange.com/questions/1424/...
ОДС
7
Я бы посмотрел на cgroups .
СЛМ
@slm Спасибо! Похоже, что cgroups это что-то попробовать. Единственное работающее решение (кроме уродливого способа суммирования памяти с использованием PS и уничтожения родительского процесса, если превышен лимит), которое может работать, - это использование какой-либо формы контейнера (lxc или тому подобное).
Jpe
Да, инструменты, о которых я знаю, делают не группу, а отдельные процессы, но учитывая то, как cgroups работают для технологий VM, таких как LXC и Docker, я ожидал, что они будут делать то, что вы хотите.
slm
1
Если это Linux, поместите родительский PID в свое собственное пространство имен и таким образом управляйте им и всеми его дочерними элементами. Вот вводный ответ на эту концепцию: unix.stackexchange.com/a/124194/52934
mikeserv

Ответы:

8

Я не уверен, отвечает ли это на ваш вопрос, но я нашел этот Perl-скрипт, который утверждает, что делает именно то, что вы ищете. Скрипт реализует свою собственную систему для обеспечения ограничений путем пробуждения и проверки использования ресурсов процесса и его дочерних элементов. Это, кажется, хорошо документировано и объяснено, и было недавно обновлено.

Как сказал slm в своем комментарии, cgroups также могут быть использованы для этого. Возможно, вам придется установить утилиты для управления cgroups, при условии, что вы находитесь в Linux, вы должны искать libcgroups.

sudo cgcreate -t $USER:$USER -a $USER:$USER -g memory:myGroup

Убедитесь, что $USERваш пользователь.

Ваш пользователь должен иметь доступ к настройкам памяти cgroup в /sys/fs/cgroup/memory/myGroup.

Затем вы можете установить ограничение, скажем, 500 МБ, выполнив следующее:

echo 500000000 > /sys/fs/cgroup/memory/myGroup/memory.limit_in_bytes

Теперь давайте запустим Vim:

cgexec -g memory:myGroup vim

Теперь процесс vim и все его дочерние элементы должны быть ограничены использованием 500 МБ ОЗУ. Тем не менее , я думаю, что это ограничение относится только к оперативной памяти, а не подкачки. Как только процессы достигнут предела, они начнут обмениваться. Я не уверен, если вы можете обойти это, я не могу найти способ ограничить использование свопа с помощью cgroups.

arnefm
источник
Предложенное решение позволяет ограничить размер резидентного набора дерева процессов. Поведение, по-видимому, отличается от RLIMIT_AS: возможно выделять больше памяти, чем является пределом, однако на самом деле невозможно больше использовать больше.
jpe
По умолчанию ограничение памяти cgroup применяется только для (приблизительно) физического использования ОЗУ. Есть опция ядра (CONFIG_MEMCG_SWAP), чтобы включить учет подкачки; см. документацию по ядру для деталей.
Сёрен Левборг
1
На Fedora,sudo yum install libcgroup-tools
Jozxyqk
2

Я создал скрипт, который делает это, используя cgmanager, который используется в Ubuntu. Одним из преимуществ является то, что для этого не требуется root-доступ. Обратите внимание, что управление cgroup немного специфично для дистрибутива, так что я не знаю, работает ли это на дистрибутивах, которые используют управление cd группой systemd.

#!/bin/sh

set -eu

if [ "$#" -lt 2 ]
then
    echo Usage: `basename $0` "<limit> <command>..."
    exit 1
fi

limit="$1"
shift
cgname="limitmem_$$"
echo "limiting memory to $limit (cgroup $cgname) for command $@"

cgm create memory "$cgname" >/dev/null
cgm setvalue memory "$cgname" memory.limit_in_bytes "$limit" >/dev/null
# try also limiting swap usage, but this fails if the system has no swap
cgm setvalue memory "$cgname" memsw.limit_in_bytes "$limit" >/dev/null 2>&1 || true

# spawn subshell to run in the cgroup
set +e
(
set -e
cgm movepid memory "$cgname" `sh -c 'echo $PPID'` > /dev/null
exec "$@"
)
# grab exit code
exitcode=`echo $?`

set -e

echo -n "peak memory used: "
cgm getvalue memory "$cgname" memory.max_usage_in_bytes | tail -1 | cut -f2 -d\"

cgm remove memory "$cgname" >/dev/null
exit $exitcode

Использование: сохранить как limitmemна вашем пути и сделать его исполняемым. Тогда беги напр limitmem 1G command.... Это ограничивает фактически используемую память. Если это будет достигнуто, убийца OOM уничтожит процесс или одного из его дочерних элементов, но не случайное событие, которое не имеет ничего общего с этой командой.

JanKanis
источник
Спасибо за краткое cgmруководство, это было полезно
Виталий Исаев
1

/unix//a/536046/4319 :

В любом системном дистрибутиве вы также можете использовать cgroups косвенно через systemd-run. Например, для вашего случая ограничения pdftoppmдо 500M RAM, используйте:

systemd-run --scope -p MemoryLimit=500M pdftoppm

...

imz - Иван Захарящев
источник