45 votes

Effets de la configuration de vm.overcommit_memory

Mon serveur Web VPS fonctionnant sous CentOS 5.4 (noyau Linux 2.6.16.33-xenU) devient de manière irrégulière (environ une fois par mois, give or take a few weeks) non répondant en raison de l'oom-killer qui se déclenche. La surveillance du serveur montre qu'il ne manque généralement pas de mémoire, seulement de temps en temps.

J'ai lu quelques blogs qui pointent vers cette page qui discute de la configuration du noyau pour mieux gérer les sur-engagements en utilisant les paramètres sysctl suivants:

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

Ma compréhension de cela (qui peut être fausse, mais je ne peux pas trouver de définition canonique pour clarifier) est que cela empêche le noyau de sur-attribuer la mémoire au-delà du swap + 80% de la mémoire physique.

Cependant, j'ai aussi lu d'autres sources suggérant que ces réglages ne sont pas une bonne idée - bien que les critiques de cette approche semblent dire "ne faites pas des choses pour casser votre système, au lieu de tenter ce bricolage" en supposant que la causalité est toujours connue.

Ma question est donc, quels sont les avantages et les inconvénients de cette approche, dans le contexte d'un serveur Web Apache2 hébergeant environ 10 sites à faible trafic ? Dans mon cas spécifique, le serveur Web dispose de 512 Mo de RAM, avec un espace d'échange de 1024 Mo. Cela semble être adéquat la majeure partie du temps.

37voto

Andriyev Points 9238

Le paramètre overcommit_ratio à 80 n'est probablement pas la bonne action. Mettre la valeur à moins de 100 est presque toujours incorrecte.

La raison en est que les applications Linux allouent plus de mémoire qu'elles n'en ont réellement besoin. Par exemple, si elles allouent 8ko pour stocker une chaîne de caractères de quelques caractères, plusieurs Ko restent inutilisés. Les applications le font souvent, c'est pourquoi l'overcommit est conçu pour cela.

Donc, essentiellement, avec un overcommit à 100, le noyau ne permettra pas aux applications d'allouer plus de mémoire que ce que vous avez (swap + RAM). Le régler à moins de 100 signifie que vous n'utiliserez jamais toute votre mémoire. Si vous devez régler ce paramètre, vous devriez le mettre plus haut que 100 en raison du scénario mentionné précédemment, qui est assez courant.
Cependant, bien que le régler à plus de 100 soit presque toujours la bonne réponse, il existe des cas d'utilisation où le régler à moins de 100 est correct. Comme mentionné précédemment, en le faisant, vous ne pourrez pas utiliser toute votre mémoire, mais le noyau le peut toujours. Vous pouvez donc effectivement utiliser cela pour réserver de la mémoire pour le noyau (par exemple, le cache de pages).

Maintenant, pour votre problème avec le déclenchement de l'OOM killer, régler manuellement l'overcommit ne résoudra probablement pas cela. Le réglage par défaut (détermination heuristique) est assez intelligent.

Si vous souhaitez vérifier si c'est réellement la cause du problème, regardez /proc/meminfo lorsque l'OOM killer se déclenche. Si vous voyez que Committed_AS est proche de CommitLimit, mais que free montre encore de la mémoire libre disponible, alors oui, vous pouvez ajuster manuellement l'overcommit pour votre scénario. Mettre cette valeur trop basse fera que l'OOM killer commencera à tuer des applications alors que vous avez encore beaucoup de mémoire libre. La régler trop haut peut provoquer la fermeture aléatoire d'applications lorsqu'elles essaient d'utiliser de la mémoire qui leur a été allouée, mais qui n'est pas réellement disponible (lorsque toute la mémoire est effectivement utilisée).

29voto

Alex North-Keys Points 521

La section 9.6 "Surcompromis et OOM" dans le document mentionné par @dunxd est particulièrement explicite sur les dangers de permettre le surcompromis. Cependant, le 80 semblait également intéressant pour moi, donc j'ai réalisé quelques tests.

Ce que j'ai découvert, c'est que le surcompromis_ratio affecte la RAM totale disponible pour TOUS les processus. Les processus racine ne semblent pas être traités différemment des processus utilisateur normaux.

Fixer le ratio à 100 ou moins devrait fournir la sémantique classique où les valeurs de retour de malloc/sbrk sont fiables. Fixer des ratios inférieurs à 100 pourrait être un moyen de réserver plus de RAM pour des activités non processus comme le mise en cache, etc.

Ainsi, sur mon ordinateur avec 24 GiB de RAM, sans swap activé, 9 GiB en cours d'utilisation, avec top montrant

Mem: 24683652k total, 9207532k utilisés, 15476120k libres, 19668k tampons
Swap: 0k total, 0k utilisés, 0k libres, 241804k mis en cache

Voici quelques paramètres du surcompromis_ratio et combien de RAM mon programme consommateur de RAM a pu allouer (touchant chaque page) - dans chaque cas, le programme s'est arrêté correctement une fois que malloc a échoué.

50 ~680 MiB
 60 ~2900 MiB
 70 ~5200 MiB
100 ~12000 MiB

Exécuter plusieurs à la fois, même avec certains en tant qu'utilisateur racine, n'a pas changé la quantité totale qu'ils ont consommée ensemble. Il est intéressant de constater qu'il était incapable de consommer les 3+ Go restants ou plus; le libre n'a pas chuté bien en dessous de ce qui est affiché ici :

Mem: 24683652k total, 20968212k utilisés, 3715440k libres, 20828k tampons

Les expériences étaient chaotiques - tout ce qui utilise malloc au moment où toute la RAM est utilisée a tendance à planter, car de nombreux programmeurs sont terribles en matière de vérification des échecs de malloc en C, certaines bibliothèques de collection populaires l'ignorent complètement, et le C++ et divers autres langages sont encore pires.

La plupart des premières implémentations de RAM imaginaire que j'ai vues visaient à traiter un cas très spécifique, où un seul gros processus - disons 51%+ de la mémoire disponible - devait fork() pour exécuter un programme de support, généralement beaucoup plus petit. Les systèmes d'exploitation avec des sémantiques de copie sur écriture permettraient le fork(), mais avec la condition que si le processus bifurqué tentait effectivement de modifier trop de pages mémoire (chacune devant alors être instanciée en tant que nouvelle page indépendante du processus initial gigantesque) il finirait par être tué. Le processus parent n'était en danger que s'il allouait plus de mémoire, et pouvait gérer le manque, dans certains cas en attendant un peu pour que d'autres processus meurent, puis en continuant. Le processus enfant se remplaçait généralement lui-même par un programme (typiquement plus petit) via exec() et était alors libéré de la condition.

Le concept de surcompromis de Linux est une approche extrême qui permet à la fois la fork() de se produire ainsi que permet aux processus individuels de s'alimenter massivement. Les décès causés par l'OOM-killer se produisent de manière asynchrone, même pour les programmes qui gèrent de manière responsable l'allocation mémoire. Je déteste personnellement le surcompromis à l'échelle du système en général et l'oom-killer en particulier - cela favorise une approche insouciante de la gestion de la mémoire qui infecte les bibliothèques et à travers elles chaque application qui les utilise.

Je suggère de régler le ratio à 100, et d'avoir également une partition de swap qui ne sera généralement utilisée que par des processus énormes - qui utilisent souvent une fraction minuscule de la partie d'eux-mêmes qui est stockée dans le swap, et protégeant ainsi la grande majorité des processus du mauvais fonctionnement de l'OOM-killer. Cela devrait protéger votre serveur web des arrêts aléatoires, et s'il a été écrit pour gérer de manière responsable malloc, même de se tuer lui-même (mais ne pariez pas là-dessus).

Cela signifie que j'utilise cela dans /etc/sysctl.d/10-no-overcommit.conf

vm.overcommit_memory = 2
vm.overcommit_ratio = 100

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X