Désactiver le tueur de MOO Linux par défaut?

37

Le tueur de MOO sous Linux fait des ravages avec diverses applications de temps en temps, et il semble que rien ne soit vraiment fait du côté du développement du noyau pour améliorer cela. Ne serait-il pas préférable, lors de la configuration d'un nouveau serveur , d'inverser la valeur par défaut du dépassement de mémoire, c'est-à-dire de le désactiver ( vm.overcommit_memory=2) sauf si vous savez que vous souhaitez l' activer pour votre usage particulier? Et quels seraient ces cas d'utilisation pour lesquels vous savez que vous souhaitez que le sur-engagement soit effectif?

En prime, puisque le comportement en cas de vm.overcommit_memory=2dépend de l' vm.overcommit_ratioespace et de l'espace de permutation, quelle serait la bonne règle pour dimensionner les deux derniers afin que toute cette installation continue de fonctionner de manière raisonnable?

Peter Eisentraut
la source

Réponses:

63

Une analogie intéressante (de http://lwn.net/Articles/104179/ ):

Une compagnie aéronautique a découvert qu’il était moins coûteux de piloter ses avions avec moins de carburant à bord. Les avions seraient plus légers et consommeraient moins de carburant, ce qui permettrait d’économiser de l’argent. En de rares occasions, la quantité de carburant était insuffisante et l'avion allait s'écraser. Ce problème a été résolu par les ingénieurs de la société grâce à la mise au point d’un mécanisme spécial d’absence de carburant. En cas d'urgence, un passager a été sélectionné et expulsé de l'avion. (Si nécessaire, la procédure a été répétée.) Un large corpus théorique a été développé et de nombreuses publications ont été consacrées au problème de la sélection correcte de la victime à éjecter. La victime devrait-elle être choisie au hasard? Ou faut-il choisir la personne la plus lourde? Ou le plus vieux? Si les passagers paient pour ne pas être éjectés, pour que la victime soit la plus pauvre à bord? Et si par exemple la personne la plus lourde était choisie, devrait-il y avoir une exception spéciale dans le cas où il s'agirait du pilote? Les passagers de première classe devraient-ils être exemptés? Maintenant que le mécanisme OOF existait, il serait activé de temps à autre et éjecterait les passagers même en l'absence de pénurie de carburant. Les ingénieurs étudient encore précisément la cause de ce dysfonctionnement.

An̲̳̳drew
la source
11
J'ai beaucoup apprécié cela, merci de l'avoir découvert.
Nick Bolton
32

Le tueur OOM ne fait des ravages que si vous avez surchargé votre système. Donnez-lui suffisamment d’échange et ne lancez pas d’applications qui décident soudainement de consommer d’énormes quantités de RAM, vous n’aurez pas de problème.

Pour répondre spécifiquement à vos questions:

  • Je ne pense pas que ce soit une bonne idée de désactiver le sur-engagement dans le cas général; très peu d'applications sont écrites pour traiter correctement brk(2) (et les wrappers qui l'utilisent, tels que malloc(3)) renvoient une erreur. Lorsque j’ai expérimenté cela dans mon travail précédent, il a été jugé plus fastidieux d’obtenir tout ce qui était capable de gérer les erreurs de mémoire insuffisante que de traiter uniquement les conséquences d’un MOO (qui, dans notre cas, était bien pire que de devoir redémarrer le service occasionnel si un MOO se produisait - nous avons dû redémarrer un cluster entier, car GFS est une pile de selles à la vapeur.
  • Vous voulez sur-engager pour tout processus qui surcharge la mémoire. Les deux principaux coupables ici sont Apache et la machine virtuelle Java, mais de nombreuses applications le font à un degré plus ou moins grand. Ils pensent qu'ils pourraient avoir besoin d' une grande quantité de mémoire à un moment donné à l'avenir, afin qu'ils saisissent un gros hors droit de morceau. Sur un système activé par la surcapacité, le noyau dit "meh, peu importe, viens me gêner quand tu veux vraiment écrire sur ces pages" et que rien ne se passe mal. Sur un système de surcommit-off, le noyau dit "non, vous ne pouvez pas avoir autant de mémoire, si vous écrivez tout cela à un moment donné dans le futur, je suis désossé, donc pas de mémoire pour vous!" et l'allocation échoue. Depuis rien"Oh, d'accord, puis-je avoir cette plus petite quantité de segment de données de processus?", le processus (a) se ferme alors avec une erreur de mémoire insuffisante ou (b) ne vérifie pas le code de retour de malloc, pense pouvoir y aller, et écrit dans un emplacement de mémoire invalide, provoquant un segfault. Heureusement, la machine virtuelle Java effectue tout son travail pré-alloué au démarrage (donc votre machine virtuelle démarre ou meurt immédiatement, ce que vous remarquez généralement), mais Apache fait des trucs géniaux à chaque nouvel enfant, ce qui peut avoir des effets excitants en production (non reproductible "ne gère pas les connexions "types d'excitation).
  • Je ne voudrais pas que mon surcommit_ratio soit supérieur à la valeur par défaut de 50%. Encore une fois, d'après mes tests, bien que définir environ 80 ou 90 puisse sembler une bonne idée, le noyau nécessite de gros morceaux de mémoire à des moments inopportuns, et un système entièrement chargé avec un taux de surcharge trop élevé risque de ne pas disposer de suffisamment de mémoire disponible. lorsque le noyau en a besoin (conduisant à la peur, à la peste et à des problèmes). Donc, jouer avec surcommit introduit un nouveau mode d'échec, encore plus amusant - plutôt que de simplement redémarrer le processus obtenu par OOM lorsque vous manquez de mémoire, votre machine tombe en panne, ce qui entraîne une panne totale de la machine. IMPRESSIONNANT!
  • L'échange d'espace dans un système dépourvu de surcapacité dépend de la quantité de mémoire demandée mais non utilisée par vos applications, plus d'une marge de sécurité suffisante. Déterminer ce qui est nécessaire dans un cas spécifique reste un exercice pour le lecteur.

D'après mon expérience, désactiver le sur-engagement est une expérience intéressante qui fonctionne rarement aussi bien dans la pratique que dans la théorie. Cela correspond bien à mes expériences avec les autres paramètres ajustables du noyau - les développeurs du noyau Linux sont presque toujours plus intelligents que vous et les valeurs par défaut sont optimales dans la très grande majorité des cas. Laissez-les tranquilles et cherchez plutôt le processus qui a la fuite et corrigez-le.

femme
la source
2
Je ne veux pas que mon processus de sauvegarde soit tué parce que quelqu'un utilise mon serveur Web. Les exceptions sont acceptables, mais la valeur par défaut doit être la sécurité et la cohérence. Les optimisations telles que le MOO doivent être activées manuellement à mon humble avis. C'est comme coder, coder proprement, puis optimiser. Le sur-envoi est une fonctionnalité intéressante, mais ne devrait pas être la valeur par défaut.
Aki
1
Si vous ne voulez pas que votre processus de sauvegarde soit tué parce que quelqu'un fait du DoS sur votre serveur Web, ne configurez pas votre serveur Web de manière à ce qu'un DoS puisse surcharger les ressources du système.
femme
J'ai 8 Go de RAM et juste en cours d'exécution avec Firefox et une machine virtuelle, le tueur de MOO tue parfois la machine virtuelle. Lors de la compilation d'Unreal Engine 4, chaque appel de résonance nécessite 1 à 1,5 Go de mémoire et, encore une fois, le tueur OOM tue de temps en temps. Maintenant, je suis généralement d'accord avec ça. Sans le tueur OOM, ils auraient probablement une erreur de segmentation de toute façon. C'est juste que chaque fois que le tueur OOM veut tuer un processus, mon système se bloque pendant 10 minutes avant que le mauvais processus ne soit réellement tué. Bug peut-être? Probablement. Est-ce que je le veux? Définitivement pas. Et c’est la raison pour laquelle vous voudrez peut-être désactiver le tueur de MOO.
Shahbaz
1
Si vous faites tout cela sur une boîte, vous avez besoin de plus de mémoire vive, et la désactivation de la surconsommation ne fera qu'aggraver les choses.
Ben Lutgens
6

Hmm, je ne suis pas totalement convaincu par les arguments en faveur de la surconsommation et du tueur OOM ... Quand womble écrit,

"Le tueur de MOO ne fait des ravages que si vous avez surchargé votre système. Donnez-lui suffisamment d'échange, et n'exécutez pas d'applications qui décident soudainement de consommer une quantité énorme de RAM, et vous n'aurez pas de problème."

Il décrit un scénario d’environnement dans lequel la surcharge et le tueur de MOO ne sont pas appliqués ou n’agissent pas vraiment (si toutes les applications allouaient de la mémoire au besoin et qu’il y avait suffisamment de mémoire virtuelle à allouer, les écritures en mémoire suivraient de près les allocations de mémoire sans erreurs, nous ne pouvons donc pas vraiment parler de système sur-engagé même si une stratégie de sur-engagement était activée). Autant que je sache (et j'avoue que je ne peux pas en dire beaucoup ...), c'est à peu près tout le monde qui admet implicitement que le surdimensionnement et le tueur OOM sont plus efficaces lorsque leur intervention n'est pas nécessaire. Cette idée est partagée par la plupart des partisans de cette stratégie. De plus, faire référence à des applications ayant des comportements spécifiques lors de la préallocation de mémoire me fait penser qu’une gestion spécifique pourrait être réglée au niveau de la distribution, au lieu d’avoir un paramètre par défaut.

En ce qui concerne la machine virtuelle Java, eh bien, il s’agit d’une machine virtuelle; elle doit, dans une certaine mesure, allouer toutes les ressources dont elle a besoin au démarrage, afin de pouvoir créer son "faux" environnement pour ses applications et de garder ses ressources disponibles séparées de l’hôte. environnement, dans la mesure du possible. Ainsi, il serait peut-être préférable qu’elle échoue au démarrage, plutôt qu’après un certain temps, à la suite d’une condition «externe» du MOO (causée par un excès de motivation / du tueur MOO / peu importe), ou de toute façon pour une telle condition interférant avec sa propre stratégies de gestion des MOO internes (en général, une machine virtuelle doit obtenir toutes les ressources requises dès le début et le système hôte doit les "ignorer" jusqu'à la fin, de la même manière que toute quantité de mémoire vive physique partagée avec une carte graphique n'est jamais - et ne peut pas être - touché par l'OS).

À propos d'Apache, je doute qu'avoir le serveur entier tué et redémarré de temps en temps soit mieux que de laisser un seul enfant, ainsi qu'une seule connexion, échouer dès le début (= de l'enfant / de la connexion) (comme s'il s'agissait d'une toute nouvelle instance de JVM créée après une autre instance exécutée pendant un certain temps). Je suppose que la meilleure "solution" pourrait dépendre d'un contexte spécifique. Par exemple, si vous envisagez un service de commerce électronique, il peut s'avérer beaucoup préférable d'avoir, parfois, quelques connexions à la carte d'achats défaillantes de manière aléatoire au lieu de perdre l'ensemble du service, avec le risque, par exemple, d'interrompre la finalisation d'une commande en cours, ou (Peut-être pire) un processus de paiement, avec toutes les conséquences de l'affaire (peut-être inoffensif, mais peut-être nuisible - et à coup sûr, lorsque des problèmes surviennent,

De la même manière, sur un poste de travail, le processus qui consomme le plus de ressources et qui constitue donc un premier choix pour le destructeur de MOO peut être une application gourmande en mémoire, telle qu'un transcodeur vidéo ou un logiciel de rendu, probablement la seule application. l'utilisateur veut rester intact. Ces considérations m'indiquent que la stratégie par défaut du tueur OOM est trop agressive. Il utilise une approche de "pire ajustement" qui est en quelque sorte similaire à celle de certains systèmes de fichiers (OOMK essaie de libérer autant de mémoire que possible, tout en réduisant le nombre de sous-processus tués, afin d'empêcher toute intervention ultérieure dans un délai aussi court. ainsi, un fs peut allouer plus d’espace disque que ce qui est réellement nécessaire pour un certain fichier, afin d’empêcher toute allocation supplémentaire si le fichier grossissait et empêchant ainsi, dans une certaine mesure, la fragmentation).

Cependant, je pense qu'une politique opposée, telle qu'une approche de "meilleur ajustement", pourrait être préférable, afin de libérer la mémoire exacte nécessaire à un moment donné, et de ne pas s'embarrasser de "gros" processus, ce qui pourrait bien être une perte de temps. mais le noyau ne peut pas le savoir (hmm, je peux imaginer que le fait de garder trace du nombre et du temps des accès à la page laisse deviner si un processus alloue de la mémoire, il n’en a plus besoin, alors devinez si un processus gaspille de la mémoire ou utilise simplement beaucoup, mais les retards d’accès doivent être pondérés en fonction des cycles cpu afin de distinguer une perte de mémoire d’ une application gourmande en mémoire et intensive, mais, même s’il est potentiellement imprécis, une telle heuristique peut entraîner une surcharge excessive.

De plus, il n’est peut-être pas vrai que tuer le moins de processus possibles est toujours un bon choix. Par exemple, dans un environnement de bureau (imaginons un nettop ou un netbook avec des ressources limitées, par exemple), un utilisateur peut exécuter un navigateur avec plusieurs onglets (consommant ainsi beaucoup de mémoire - supposons qu'il s'agisse du premier choix pour OOMK). , plus quelques autres applications (un traitement de texte avec des données non sauvegardées, un client de messagerie, un lecteur de pdf, un lecteur multimédia, ...), quelques démons (système), plus quelques instances de gestionnaire de fichiers. Maintenant, une erreur de MOO se produit et le MOQ choisit de tuer le navigateur pendant que l'utilisateur fait quelque chose qui est jugé "important" sur le net ... l'utilisateur serait déçu. Par contre, fermer le gestionnaire de fichiers

Quoi qu'il en soit, je pense que l'utilisateur devrait avoir la possibilité de prendre lui-même la décision. Dans un système de bureau (= interactif), cela devrait être relativement facile à faire, à condition que suffisamment de ressources soient réservées pour demander à l'utilisateur de fermer n'importe quelle application (même fermer quelques onglets pourrait suffire) et gérer son choix (une option pourrait consiste à créer un fichier d'échange supplémentaire, s'il y a suffisamment d'espace). Pour les services (et en général), j’envisageais également deux autres améliorations possibles: l’une consiste à consigner les intervalles tueurs de MOO, ainsi que les processus démarrant / forçant les échecs de telle manière que l’échec puisse être facilement débogué (par exemple, une API informer le processus à l'origine de la création ou de la création du nouveau processus - ainsi, un serveur comme Apache, doté du correctif approprié, pourrait fournir une meilleure journalisation pour certaines erreurs); cela pourrait être fait indépendamment du sur-engagement / OOMK en cours d'effort; en second lieu, mais sans importance, un mécanisme pourrait être mis en place pour affiner l'algorithme OOMK - je sais qu'il est possible, dans une certaine mesure, de définir une politique spécifique processus par processus, mécanisme de configuration «centralisé», basé sur une ou plusieurs listes de noms d'applications (ou id) pour identifier les processus pertinents et leur attribuer un certain degré d'importance (selon les attributs répertoriés); un tel mécanisme devrait (ou du moins pourrait) être également stratifié, de sorte qu’il puisse y avoir une liste de niveau supérieur définie par l’utilisateur, une liste définie par le système (distribution), et des entrées définies par l’application (au niveau inférieur) , par exemple, un gestionnaire de fichiers DE peut demander à OOMK de tuer en toute sécurité toute instance,

De plus, une API pourrait être fournie afin de permettre aux applications d’augmenter ou de réduire leur niveau «d’importance» au moment de l’exécution (en ce qui concerne la gestion de la mémoire et quelle que soit la priorité d’exécution), de sorte que, par exemple, un traitement de texte puisse démarrer avec une «importance» faible, mais augmentez-la au fur et à mesure que certaines données sont conservées avant le vidage dans un fichier, ou une opération d'écriture est en cours d'exécution, et diminuez à nouveau son importance une fois que cette opération se termine (de manière analogue, un gestionnaire de fichiers peut changer de niveau lorsqu'il passe Lit des fichiers pour traiter des données et vice-versa, au lieu d’utiliser des processus distincts, et Apache pourrait attribuer différents niveaux d’importance à différents enfants, ou modifier un état enfant conformément à une politique définie par les administrateurs système et exposée via le serveur Apache - ou tout autre type de serveur. - paramètres). Bien sûr, une telle API pourrait et serait mal utilisée, mais je pense que c'est une préoccupation mineure par rapport au noyau qui tue arbitrairement des processus pour libérer de la mémoire sans aucune information pertinente sur ce qui se passe sur le système (et sur la consommation de mémoire / le moment de la création ou autre) pas assez pertinent ou "valider" pour moi) - seuls les utilisateurs, les administrateurs et les rédacteurs de programme peuvent vraiment déterminer si un processus est "encore nécessaire" pour une raison quelconque, quelle est la raison et / ou si l'application est dans un état avancé à la perte de données ou autres dommages / troubles si tués; cependant, certaines hypothèses pourraient encore être faites, par exemple la recherche de ressources d'un certain type (descripteurs de fichier, sockets réseau, etc.) acquises par un processus et avec des opérations en attente pourrait indiquer si un processus doit être dans un "état" supérieur le seul ensemble,

Ou bien, évitez simplement de surcharger et laissez le noyau faire ce qu’il doit faire, allouer des ressources (sans les sauver arbitrairement comme le fait le tueur de MOO), planifier des processus, éviter les famines et les blocages (ou les sauver), assurer la préemption et séparation des espaces mémoire, etc.

Je passerais également quelques mots sur les approches de sur-engagement. D’autres discussions, j’ai suggéré qu’une des principales préoccupations concernant le sur-engagement (à la fois en tant que raison de le vouloir et en tant que source de problèmes possibles) consiste en une manipulation des fourchettes: honnêtement, je ne sais pas exactement comment la stratégie en écriture est mise en œuvre, mais je pense que toute stratégie agressive (ou optimiste) pourrait être atténuée par une stratégie de localité à échange similaire. C'est-à-dire qu'au lieu de simplement cloner (et ajuster) un processus et des structures de planification de processus découpés, quelques autres pages de données pourraient être copiées avant une écriture réelle, en choisissant parmi les pages auxquelles le processus parent a accédé plus fréquemment (c'est-à-dire, utiliser un compteur pour les opérations d'écriture).

Tout, bien sûr, à mon humble avis.


la source
5
"De plus, une API pourrait être fournie afin de permettre aux applications d'augmenter ou de réduire leur niveau" d'importance "au moment de l'exécution" L'importance est /proc/$PID/oom_adj.
Vi.
1
En ce qui concerne la machine virtuelle Java, il existe un piège qui vous oblige parfois à demander une mémoire surchargée: si vous souhaitez créer une autre machine virtuelle à partir de votre machine virtuelle d'origine, elle appelle fork (). Un appel fork va allouer autant de mémoire que le processus original (en premier), jusqu'à ce qu'il commence réellement le processus. Supposons donc que vous avez une machine virtuelle Java de 4 Go et que vous souhaitez créer une nouvelle machine virtuelle Java de 512 Ko, à moins que vous n'ayez trop de travail, vous aurez besoin de 8 Go de mémoire pour le faire ...
alci
4
@Vi. Semble maintenant est/proc/$PID/oom_score_adj
m3nda
1

Si les processus épuisent votre mémoire de manière excessive, ce qui peut éventuellement menacer la stabilité du système, le destructeur de MOO entre en scène. Le tueur de MOO a la tâche de tuer les processus jusqu'à ce que suffisamment de mémoire soit libérée pour le bon déroulement du processus. Le tueur OOM doit sélectionner le "meilleur" processus à tuer. "Meilleur" fait ici référence à ce processus qui libérera une mémoire maximale lors de la mise à mort et qui est également moins important pour le système. L'objectif principal est de supprimer le plus petit nombre de processus possible afin de minimiser les dommages causés tout en maximisant la quantité de mémoire libérée. Pour faciliter cela, le noyau maintient oom_score pour chacun des processus. Vous pouvez voir le oom_score de chacun des processus dans le système de fichiers / proc sous le répertoire pid

# cat /proc/10292/oom_score

Plus la valeur de oom_score d'un processus est élevée, plus sa probabilité d'être tué par le tueur MOM est grande, plus le nombre de morts est élevé.

Crédit: - Le noyau Linux lance le tueur de MOO

Dinkey Jhanwar
la source