Effets de la configuration de vm.overcommit_memory

41

Mon serveur Web VPS fonctionnant sur CentOS 5.4 (noyau Linux 2.6.16.33-xenU) de manière irrégulière (une fois par mois, à quelques semaines près) cesse de répondre en raison de la mise en route de OOM-Killer. Le contrôle du serveur montre que ce n'est pas le cas. normalement à court de mémoire, de temps en temps.

J'ai lu quelques blogs pointant vers cette page, qui traitent de la configuration du noyau pour mieux gérer les surcharges à l'aide des paramètres sysctl suivants:

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

D'après ce que je comprends (ce qui peut être faux, mais je ne trouve pas de définition canonique à clarifier), cela empêche le noyau de sur-allouer de la mémoire au-delà de l'échange + 80% de la mémoire physique.

Cependant, j'ai lu aussi quelques autres sources suggérant que ces paramètres ne sont pas une bonne idée - même si les critiques de cette approche semblent dire « ne pas faire les choses à briser votre système, plutôt que de tenter cette bidouille » dans l'hypothèse que la causalité est toujours connue.

Ma question est donc la suivante: 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 particulier, le serveur Web dispose de 512 Mo de RAM, avec 1024 Mo d’espace de permutation. Cela semble être suffisant pour la grande majorité du temps.

dunxd
la source

Réponses:

32

Définir overcommit_ratioà 80 n'est probablement pas la bonne action. Définir une valeur inférieure à 100 est presque toujours incorrect.

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

En résumé, 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). En le réglant à moins de 100, vous n'utiliserez jamais toute votre mémoire. Si vous souhaitez définir ce paramètre, vous devez le définir à une valeur supérieure à 100 en raison du scénario susmentionné, qui est assez courant.

Maintenant, en ce qui concerne votre problème avec le déclenchement du tueur OOM, définir manuellement le sur-engagement ne résoudra probablement pas le problème. Le paramètre par défaut (détermination heuristique) est assez intelligent.

Si vous souhaitez savoir si cela est vraiment la cause du problème, examinez à /proc/meminfoquel moment le tueur OOM est exécuté. Si vous voyez que cela Committed_ASest proche de CommitLimit, mais que vous avez freetoujours de la mémoire libre disponible, alors vous pouvez ajuster manuellement le surengagement de votre scénario. Si vous définissez cette valeur sur une valeur trop faible, le destructeur de MOO commencera à supprimer des applications alors qu'il vous reste encore beaucoup de mémoire. Si vous le définissez trop haut, des applications aléatoires risquent de disparaître lorsqu'elles essaient d'utiliser la mémoire allouée, mais n'est pas réellement disponible (lorsque toute la mémoire est réellement utilisée).

Patrick
la source
1
Merci - j'essaie des choses avec surcommit_ratio réglé à 100 pour voir ce qui se passe. Le principal problème que j'ai est que lorsque OOM-Killer démarre, il tue invariablement sshd, m'empêchant d'accéder au serveur et de voir ce qui se passe. Je suppose que ce dont j'ai vraiment besoin, c’est d’empêcher Oom-Killer de courir et de disposer d’un moyen d’enregistrer ce qui se passe quand il aurait fonctionné afin que je puisse trouver la cause du problème.
dimanche
4
@dunxd vous pouvez utiliser /proc/<PID>/oom_score_adjà cette fin. Par exemple, si vous définissez oom_score_adj sur -1000 pour sshd, le tueur à mort ne ciblera jamais sshd lorsqu'il voudra tuer quelque chose. Arrêter complètement Kom Killer n’est pas une bonne idée car vos programmes ne seront plus capables de mémoire, et ils mourront de toute façon.
Patrick
4
@dunxd son hérité. demandez à votre script init de le définir sur lui-même et tout élément démarré par le script init en hérite.
Patrick
4
Votre exemple de 4 Ko est faux. La mémoire virtuelle est utilisée avec les pages et la taille (la plus petite) d’une page sous Linux est de 4 Ko. Cela signifie que pour stocker quelques caractères, il faut que 4 Ko soient mappés quelque part, quels que soient les paramètres de surengagement. Par exemple, vous allouez 10 Ko et n'utilisez que les 4100 premiers octets. Cela signifie que deux pages de 4 Ko doivent stocker les données et qu'une page supplémentaire est inutilisée. Les systèmes non surcommitants auront toujours cette troisième page prête à stocker des données si la demande arrive, les systèmes de validation ne le feront pas respecter.
Juillet
2
/ proc / self pointe vers le processus en cours, de sorte que / proc / self / oom_score_adj pourrait être utilisé pour modifier oom_score_adj du processus en cours.
r_2
23

La section 9.6 "Surcommission et MOO" dans la documentation mentionnée par @dunxd est particulièrement graphique sur les dangers de permettre une sur-utilisation. Cependant, cela 80m’intéressait aussi et j’ai donc fait quelques tests.

Ce que j'ai trouvé, c'est que cela overcommit_ratioaffecte 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 à 100ou moins devrait fournir la sémantique classique pour laquelle les valeurs renvoyées malloc/sbrksont fiables. Définir des ratios inférieurs à ce qui 100pourrait être un moyen de réserver plus de RAM pour des activités non liées au processus telles que la mise en cache, etc.

Donc, sur mon ordinateur avec 24 Go de RAM, avec permutation désactivée, 9 Go en cours d'utilisation, avec topaffichage

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

Voici quelques overcommit_ratioparamètres et la quantité de RAM que mon programme consommateur-ram peut prendre (en touchant chaque page) - dans chaque cas, le programme est sorti proprement une fois en mallocéchec.

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

En exécuter plusieurs à la fois, même si certains en sont l'utilisateur root, n'a pas modifié la quantité totale consommée ensemble. Il est intéressant de noter qu’il n’a pas été en mesure de consommer les 3 derniers GiB ou plus; le freen'a pas chuté beaucoup en dessous de ce qui est montré ici:

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

Les expériences étaient désordonnées - tout ce qui utilise malloc au moment où toute la RAM est utilisée a tendance à planter, car de nombreux programmeurs ne savent pas comment vérifier les échecs de malloc en C, certaines bibliothèques de collections populaires l'ignorent entièrement, et C ++ et d'autres langages le sont également. pire.

La plupart des premières implémentations de RAM imaginaire que j'ai vues concernaient un cas très spécifique, dans lequel un seul processus volumineux - disons 51% + de mémoire disponible - était nécessaire pour pouvoir mettre fork()en place exec()un programme de support, généralement beaucoup plus petit. Les systèmes d'exploitation avec une sémantique de copie sur écriture le permettent fork(), mais à condition que si le processus forké tente réellement de modifier trop de pages mémoire (chacune d'entre elles devrait ensuite être instanciée comme une nouvelle page indépendante du processus énorme initial) il finirait par se faire tuer. Le processus parent n'était en danger que si l'on allouait plus de mémoire et pouvait gérer l'épuisement des stocks, dans certains cas, il suffisait d'attendre un peu qu'un autre processus meure, puis de continuer. Le processus enfant vient généralement de se remplacer par un programme (généralement plus petit) viaexec() et était alors libre de la condition.

Le concept de surengagement de Linux est une approche extrême permettant à la fois fork()de se produire et de permettre à des processus uniques d’alléger massivement. Décès causés OOM-tueuses se produisent de manière asynchrone, même aux programmes qui font la poignée allocation de mémoire de façon responsable. Personnellement, je déteste la surcharge de travail à l’ échelle du système en général et celle de l’Oom-killer en particulier - elle favorise une approche diabolique de la gestion de la mémoire qui infecte les bibliothèques et, par leur intermédiaire, toutes les applications qui les utilisent.

Je suggèrerais de fixer le rapport à 100 et d’avoir également une partition de swap qui ne serait généralement utilisée que par d’énormes processus - qui utilisent souvent une infime fraction de la partie de leur vie qui est bourrée dans le swap, et donc protéger la grande majorité des processus du mauvais fonctionnement du tueur OOM. Cela devrait garder votre serveur Web à l'abri d'une mort aléatoire, et s'il a été écrit pour le gérer de manière mallocresponsable, même s'il ne risque pas de se tuer (mais ne pariez pas sur ce dernier).

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

vm.overcommit_memory = 2
vm.overcommit_ratio = 100
Alex North-Keys
la source
Et recommanderiez-vous de garder vm.overcommit_memory à 2?
Ut xD
1
Bonne note - c'est effectivement ce que j'utilise; Je pense l'avoir omis dans ma réponse parce que c'est déjà dans la question
Alex North-Keys