web-dev-qa-db-fra.com

Effets de la configuration de vm.overcommit_memory

Mon serveur Web VPS fonctionnant sous CentOS 5.4 (noyau Linux 2.6.16.33-xenU) de manière irrégulière (comme une fois par mois, donne ou prend quelques semaines) ne répond plus en raison d'un coup de pied oom-killer. La surveillance du serveur montre qu'il ne fonctionne pas manque généralement de mémoire, juste de temps en temps.

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

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

Ma compréhension de cela (ce qui peut être faux, mais je ne trouve pas de définition canonique à clarifier) ​​est que cela empêche le noyau de surallouer la mémoire au-delà du swap + 80% de la mémoire physique.

Cependant, j'ai également lu certains d'autres sources suggérant que ces paramètres ne sont pas une bonne idée - bien que les critiques de cette approche semblent dire "ne faites rien pour casser votre système, plutôt que d'essayer ce kludge "dans l'hypothèse 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 une dizaine de sites à faible trafic? Dans mon cas spécifique, le serveur Web a 512 Mo de RAM, avec 1024 Mo d'espace de swap. Cela semble suffisant pour la grande majorité du temps.

41
dunxd

Réglage overcommit_ratio à 80 n'est probablement pas la bonne action. La définition d'une valeur inférieure à 100 est presque toujours incorrecte.

La raison en est que les applications Linux allouent plus que ce dont elles ont vraiment besoin. Supposons qu'ils allouent 8 Ko pour stocker une chaîne de texte de deux caractères. Eh bien, c'est plusieurs Ko non utilisés ici. Les applications font beaucoup cela, et c'est pour cela que le sur-engagement est conçu.

Donc, fondamentalement, avec une surcharge de 100, le noyau ne permettra pas aux applications d'allouer plus de mémoire que vous n'en avez (swap + ram). Le définir à moins de 100 signifie que vous n'utiliserez jamais toute votre mémoire. Si vous allez définir ce paramètre, vous devez le définir supérieur à 100 en raison du scénario susmentionné, ce qui est assez courant.

Maintenant, en ce qui concerne votre problème avec le déclenchement du tueur OOM, le réglage manuel de la surcharge ne résoudra probablement pas cela. Le paramètre par défaut (détermination heuristique) est assez intelligent.

Si vous souhaitez voir si c'est vraiment la cause du problème, regardez /proc/meminfo lorsque le tueur OOM s'exécute. Si vous voyez que Committed_AS est proche de CommitLimit, mais free affiche toujours de la mémoire disponible, alors oui, vous pouvez régler manuellement la surcharge de votre scénario. Si vous définissez cette valeur sur une valeur trop basse, le tueur OOM commencera à tuer les applications lorsque vous aurez encore beaucoup de mémoire libre. Une valeur trop élevée peut entraîner la mort d'applications aléatoires lorsqu'elles tentent d'utiliser la mémoire qui leur a été allouée, mais n'est pas réellement disponible (lorsque toute la mémoire est effectivement utilisée).

33
Patrick

La section 9.6 "Overcommit and OOM" dans le document mentionné par @dunxd est particulièrement graphique sur les dangers de permettre une sur-validation. Cependant, le 80 Me semblait également intéressant, j'ai donc effectué quelques tests.

Ce que j'ai trouvé, c'est que le overcommit_ratio Affecte le total RAM disponible pour TOUS les processus. Les processus racine ne semblent pas être traités différemment des processus utilisateur normaux.

La définition du ratio sur 100 Ou moins devrait fournir la sémantique classique où les valeurs de retour de malloc/sbrk Sont fiables. La définition de ratios inférieurs à 100 Pourrait être un moyen de réserver davantage RAM pour des activités non liées au processus comme la mise en cache, etc.).

Donc, sur mon ordinateur avec 24 GiB de RAM, avec swap désactivé, 9 GiB en cours d'utilisation, avec top montrant

Mem:  24683652k total,  9207532k used, 15476120k free,    19668k buffers
Swap:        0k total,        0k used,        0k free,   241804k cached

Voici quelques paramètres overcommit_ratio Et combien RAM mon programme de consommateur de RAM pourrait saisir (toucher chaque page) - dans chaque cas, le programme s'est terminé proprement une fois malloc échoué.

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

En exécuter plusieurs à la fois, même avec certains en tant qu'utilisateur root, n'a pas changé la quantité totale qu'ils ont consommée ensemble. Il est intéressant de noter qu'il n'a pas pu consommer les 3+ derniers GiB environ; le free n'est pas descendu bien en dessous de ce qui est montré ici:

Mem:  24683652k total, 20968212k used,  3715440k free,    20828k buffers

Les expériences étaient compliquées - tout ce qui utilise malloc en ce moment tout RAM est utilisé a tendance à planter, car de nombreux programmeurs sont terribles à propos de la recherche d'échecs de malloc en C, certaines bibliothèques de collections populaires l'ignorent complètement , et C++ et divers autres langages sont encore pires.

La plupart des premières implémentations de l'imaginaire RAM j'ai vu étaient destinées à gérer un cas très spécifique, où un seul grand processus - disons 51% + de mémoire disponible - avait besoin de fork() afin de exec() un programme de support, généralement beaucoup plus petit. Les OS avec la sémantique de copie sur écriture autoriseraient la fork(), mais à condition que si le processus forké essayait en fait de modifier trop de pages de mémoire (chacune devant ensuite être instanciée comme une nouvelle page indépendante de l'énorme processus initial), elle finirait par être tuée. Le processus parent n'était en danger que s'il allouait plus de mémoire et pouvait gérer l'exécution, dans certains cas, juste en attendant un peu qu'un autre processus meure, puis en continuant. Le processus enfant vient généralement de se remplacer par un programme (généralement plus petit) via exec() et était alors libre de la réserve.

Le concept de sur-engagement de Linux est une approche extrême pour permettre à la fois à la fork() de se produire ainsi qu'à permettre à des processus uniques de sur-utiliser massivement. Les décès causés par les tueurs OOM se produisent de manière asynchrone, même pour les programmes qui font gèrent l'allocation de mémoire de manière responsable. Personnellement, je déteste à l'échelle du système surcharger en général et le tueur en chef en particulier - il favorise une approche diabolique de la gestion de la mémoire qui infecte les bibliothèques et à travers elles toutes les applications qui les utilisent.

Je suggérerais de définir le ratio à 100 et d'avoir une partition de swap qui ne finirait généralement par être utilisée que par d'énormes processus - qui n'utilisent souvent qu'une infime partie de la partie d'eux-mêmes qui est remplie de swap, et donc protéger la grande majorité des processus contre les anomalies du tueur OOM. Cela devrait garder votre serveur Web à l'abri d'une mort aléatoire, et s'il a été écrit pour gérer malloc de manière responsable, même à l'abri de se tuer (mais ne pariez pas sur ce dernier).

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

vm.overcommit_memory = 2
vm.overcommit_ratio = 100
24
Alex North-Keys