Comment limiter les ressources totales (mémoire) d'un processus et de ses enfants

16

Il y a beaucoup de questions et réponses sur la contrainte des ressources d'un seul processus, par exemple RLIMIT_AS peut être utilisé pour contraindre la mémoire maximale allouée par un processus qui peut être vu comme VIRT dans les goûts de top. Plus d'informations sur le sujet, par exemple ici Existe-t-il un moyen de limiter la quantité de mémoire qu'un processus particulier peut utiliser sous Unix?

setrlimit(2) la documentation dit:

Un processus enfant créé via fork (2) hérite des limites de ressources de son parent. Les limites de ressources sont préservées dans execve (2).

Il doit être compris de la manière suivante:

Si un processus a un RLIMIT_AS de 2 Go par exemple, il ne peut pas allouer plus de mémoire que 2 Go. Lorsqu'il engendre un enfant, la limite d'espace d'adressage de 2 Go est transmise à l'enfant, mais le comptage commence à 0. Les 2 processus ensemble peuvent prendre jusqu'à 4 Go de mémoire.

Mais quelle serait la manière utile de contraindre la somme totale de mémoire allouée par un arbre entier de processus?

jpe
la source
7
Je jetterais un coup d'oeil aux cgroups .
slm
@slm Merci! On dirait que cgroups est quelque chose à essayer. La seule solution qui fonctionne jusqu'à présent (en plus d'une façon laide de sommer la mémoire en utilisant PS et de tuer le processus parent si au-dessus de la limite) qui pourrait fonctionner est d'utiliser une certaine forme de conteneur (lxc ou autres).
jpe
Ouais - les outils que je connais ne font pas un groupe, juste des processus uniques, mais étant donné le fonctionnement des cgroups pour les technologies VM comme LXC et Docker, je m'attendrais à ce qu'il fasse ce que vous voulez.
slm
1
Si c'est Linux, mettez le PID parent dans son propre espace de noms et contrôlez-le ainsi que tous ses enfants. Voici une réponse introductive à ce concept: unix.stackexchange.com/a/124194/52934
mikeserv

Réponses:

8

Je ne sais pas si cela répond à votre question, mais j'ai trouvé ce script perl qui prétend faire exactement ce que vous recherchez. Le script implémente son propre système pour appliquer les limites en se réveillant et en vérifiant l'utilisation des ressources du processus et de ses enfants. Il semble bien documenté et expliqué, et a été mis à jour récemment.

Comme l'a dit slm dans son commentaire, les groupes de contrôle peuvent également être utilisés pour cela. Vous devrez peut-être installer les utilitaires de gestion des cgroups, en supposant que vous êtes sous Linux, vous devez rechercher libcgroups.

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

Assurez-vous que $USERc'est votre utilisateur.

Votre utilisateur devrait alors avoir accès aux paramètres de mémoire de cgroup dans /sys/fs/cgroup/memory/myGroup.

Vous pouvez ensuite définir la limite à, disons 500 Mo, en procédant comme suit:

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

Permet maintenant d'exécuter Vim:

cgexec -g memory:myGroup vim

Le processus vim et tous ses enfants devraient maintenant se limiter à utiliser 500 Mo de RAM. Cependant , je pense que cette limite ne s'applique qu'à la RAM et non au swap. Une fois que les processus atteignent la limite, ils commenceront à échanger. Je ne sais pas si vous pouvez contourner cela, je ne peux pas trouver un moyen de limiter l'utilisation de swap à l'aide de cgroups.

arnefm
la source
La solution proposée permet de limiter la taille de l'ensemble résident d'un arbre de processus. Le comportement semble être différent de RLIMIT_AS: il est possible de malloc plus de mémoire que la limite, mais il ne semble pas possible d'en utiliser réellement plus.
jpe
Par défaut, la limite de mémoire de cgroup s'applique uniquement (approximativement) à l'utilisation de la RAM physique. Il existe une option de noyau (CONFIG_MEMCG_SWAP) pour activer la comptabilité de swap; voir la documentation du noyau pour plus de détails.
Søren Løvborg
1
Sur fedora,sudo yum install libcgroup-tools
jozxyqk
2

J'ai créé un script qui fait cela, en utilisant cgmanager qui est utilisé dans Ubuntu. Un avantage est que cela ne nécessite pas d'accès root. Notez que la gestion de groupe de contrôle est un peu spécifique à la distribution, donc je ne sais pas si cela fonctionne sur les distributions qui utilisent la gestion de groupe de système.

#!/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

utilisation: enregistrez comme limitmemdans votre chemin et rendez-le exécutable. Exécutez ensuite par exemple limitmem 1G command.... Cela limite la mémoire réellement utilisée. Si cela est atteint, le tueur OOM tuera le processus ou l'un de ses enfants, mais pas quelque chose de aléatoire qui n'a rien à voir avec cette commande.

JanKanis
la source
Merci pour le petit cgmguide, c'était utile
Vitaly Isaev
1

/unix//a/536046/4319 :

Sur n'importe quelle distribution basée sur systemd, vous pouvez également utiliser des cgroups indirectement via systemd-run. Par exemple pour votre cas de limitation pdftoppmà 500M de RAM, utilisez:

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

...

imz - Ivan Zakharyaschev
la source