Як обмежити загальні ресурси (пам'ять) процесу та його дітей


16

Є багато запитань та відповідей щодо обмеження ресурсів одного процесу, наприклад, RLIMIT_AS може використовуватися для обмеження максимальної пам'яті, виділеної процесом, який можна розглядати як VIRT у подібних top. Більше про тему, наприклад, тут Чи є спосіб обмежити об'єм пам'яті, який певний процес може використовувати в Unix?

setrlimit(2) документація говорить:

Дочірній процес, створений за допомогою fork (2), успадковує обмеження ресурсів свого батька. Обмеження ресурсів зберігається через execve (2).

Це слід розуміти так:

Якщо процес має RLIMIT_AS, наприклад 2 Гб, він не може виділити більше пам'яті, ніж 2 ГБ. Коли вона нерестує дитину, обмеження адресного простору в 2 ГБ буде передано дитині, але підрахунок починається від 0. Два разом процеси можуть займати до 4 Гб пам'яті.

Але який би був корисний спосіб обмежити загальну суму пам'яті, виділену цілим деревом процесів?



7
Я приймаю би поглянути на контрольних групах .
slm

@slm Дякую! Звучить, як угруповання - щось спробувати. Наразі єдиним робочим рішенням (окрім некрасивого способу підбиття пам'яті за допомогою PS та знищення батьківського процесу, якщо вище обмеження), що може працювати, є використання якоїсь форми контейнера (lxc або подібних).
jpe

Так - інструменти, про які я знаю, не роблять групу, а лише поодинокі процеси, але враховуючи, як працюють групи для таких технологій VM, як LXC та Docker, я б очікував, що вони будуть робити те, що ви хочете.
slm

1
Якщо це Linux, покладіть батьківський PID у власний простір імен і контролюйте його та всіх його дітей таким чином. Ось вступна відповідь до цієї концепції: unix.stackexchange.com/a/124194/52934
mikeserv

Відповіді:


8

Я не впевнений, чи відповідає це на ваше запитання, але я знайшов цей сценарій perl, який вимагає робити саме те, що ви шукаєте. Сценарій реалізує власну систему забезпечення обмежень шляхом пробудження та перевірки використання ресурсів процесу та його дітей. Здається, це добре задокументовано та пояснено, і нещодавно оновлено.

Як сказала slm у своєму коментарі, для цього також можуть бути використані групи. Можливо, вам доведеться встановити утиліти для управління групами, припускаючи, що ви перебуваєте в Linux, що вам слід шукати libcgroups.

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

Переконайтесь, що $USERце ваш користувач.

Тоді ваш користувач повинен мати доступ до налаштувань пам'яті групи в /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 Мб оперативної пам’яті. Однак я думаю, що цей ліміт стосується лише оперативної пам’яті, а не swap. Як тільки процеси досягнуть межі, вони почнуть змінюватися. Я не впевнений, чи зможете ви обійти це питання, я не можу знайти спосіб обмеження використання свопів за допомогою cgroups.


Запропоноване рішення дає можливість обмежити розмір набору резидентів дерева процесів. Поведінка, схоже, відрізняється від RLIMIT_AS: можна зменшити більше пам'яті, ніж межа, проте, здається, неможливо реально використовувати більше.
jpe

За замовчуванням обмеження пам’яті групової групи застосовується лише до (приблизно) фізичного використання ОЗУ. Існує варіант ядра (CONFIG_MEMCG_SWAP), щоб увімкнути обмін свопом; див. Документи ядра для деталей.
Søren Løvborg

1
На Fedora,sudo yum install libcgroup-tools
jozxyqk

2

Я створив сценарій, який робить це, використовуючи cgmanager, який використовується в Ubuntu. Одна перевага полягає в тому, що для цього не потрібен кореневий доступ. Зауважте, що управління групами трохи специфічно для дистрофу, тому я не знаю, чи працює це на дистрибутивах, які використовують системне управління групами.

#!/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 вбиває процес або одного з його дітей, але не щось випадкове, що не має нічого спільного з цією командою.


Дякую за короткий cgmдовідник, він був корисним
Віталій Ісаєв

1

/unix//a/536046/4319 :

У будь-якому дистрибутиві, який базується на системі, ви також можете використовувати групи непрямим шляхом через системний запуск. Наприклад, у випадку обмеження pdftoppmдо 500 млн оперативної пам’яті, використовуйте:

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

...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.