71 votes

empêcher le gel du système/la non-réponse en raison de l'utilisation de la mémoire par swapping.

Si un processus demande beaucoup de mémoire, le système déplace tous les autres processus vers le fichier d'échange. Y compris, semble-t-il, les processus nécessaires comme le serveur X11 ou le terminal.

Donc, si un processus continue à allouer sans limite, tout devient insensible, jusqu'à ce que ce processus soit tué par l'OOM-killer. Mon ordinateur portable semble être particulièrement sensible et réagit extrêmement mal. Je viens de passer une HEURE ENTIÈRE à attendre la fin du processus, pendant laquelle on ne pouvait même pas déplacer le curseur de la souris.

Comment éviter cela ?

1) Désactiver le swap => je lance souvent beaucoup de processus qui deviennent ensuite inactifs. Les processus inactifs devraient être déplacés vers le swap.

2) Acheter un SSD => trop cher

3) définir un ulimit maximum de mémoire => mais cela échoue dans les cas où un programme a besoin d'une quantité raisonnable et importante de mémoire. le problème n'est pas qu'il en utilise trop, mais qu'il supprime les autres processus.

4) garder les programmes importants (X11, bash, kill, top, ...) en mémoire et ne jamais les échanger => est-ce possible ? comment ? peut-être n'échanger que les gros programmes ?

5) ?

64voto

JPvRiel Points 1351

TL;DR

Réponse courte

  • Le plus facile : Utilisez une version de Linux plus récente où systemd-oomd est devenu une partie de systemd au cours du 2e semestre 2020.
    • Sinon, ayez une partition swap plus petite et évitez que le noyau n'essaie de faire croire qu'il n'y a pas de limite de mémoire en exécutant des processus à partir d'un stockage lent au lieu de la RAM.
    • Avec un gros swap, le traditionnel OOM (out of memory manager) de l'espace noyau n'a pas agi assez tôt. Typiquement, il comptabilise en fonction de la mémoire virtuelle et, dans mon expérience passée (avec Ubuntu 16.04), il n'a pas tué les choses avant que le swap entier ne soit rempli. D'où le système qui s'agite et qui rampe...
  • Vous avez besoin d'un gros échange pour hibernation et vous êtes coincé avec une ancienne version de systemd sans systemd-oomd intégré ?
    • Pour tester : essayez d'ajouter oomd séparément sur les systèmes avec cgroup2 et psi disponibles (par exemple Ubuntu 20.04, qui ne dispose pas de systemd-oomd). OOMD est "un tueur hors mémoire de l'espace utilisateur" qui examine la pression d'utilisation de la mémoire physique active par le biais de nouvelles métriques Pressure Stall Information (PSI). Il devrait donc agir plus rapidement que l'OOM du noyau et agir avant que le système ne soit surchargé jusqu'à une utilisation extrême du swap.
  • Vous êtes coincé sur un ancien système sans cgroup2 ?
    • Tentative/problème : Fixer certains ulimits (par exemple, vérifier ulimit -v et peut-être fixer une limite stricte ou souple à l'aide de l'option as option dans limits.conf ). Cela fonctionnait assez bien auparavant, mais grâce à l'introduction de WebKit gigacage De nombreuses applications gnome s'attendent maintenant à des espaces d'adressage illimités et ne fonctionnent pas !
    • Tentative/problème : La politique et le ratio de surengagement sont une autre façon d'essayer de gérer et d'atténuer ce problème (par ex. sysctl vm.overcommit_memory , sysctl vm.overcommit_ratio mais cette approche n'a pas fonctionné pour moi.
    • Difficile/compliqué : Essayer d'appliquer une priorité cgroup aux processus les plus importants (par exemple ssh), mais cela semble actuellement lourd pour cgroup v1 (cgroup v2 est censé le rendre plus facile)....

J'ai aussi trouvé :

Réponse longue et contexte

En 2021, plusieurs améliorations du noyau Linux (cgroups v2, psi, meilleur contrôle de l'écriture des pages), ainsi que systemd-oomd, ont fait leur chemin dans les nouvelles versions des distros.

Notez que de nombreuses améliorations du contrôle des ressources de cgroup et de son support par systemd ne sont pas exploitées par défaut. Pour les cas d'utilisation de bureau, cela nécessite un réglage manuel de la part de l'utilisateur final.

Les entreprises traditionnelles de distribution de Linux qui ont des équipes de développement à plein temps, par exemple RedHat (CentOS/Fedora), SUSE ou Ubuntu (Debian), se concentrent probablement sur les cas d'utilisation côté serveur en tant que priorité plus élevée que la réactivité du bureau. Peut-être que l'écosystème Android est un endroit plus susceptible d'attirer Linux vers les besoins de réactivité des dispositifs informatiques des utilisateurs finaux, mais cela n'aidera pas beaucoup étant donné que l'init utilisé sur Android n'est pas systemd, et donc au-delà du noyau, il n'y a pas beaucoup de bénéfice partagé. De plus, le noyau empaqueté pour Android est probablement configuré et construit différemment.

Quelques patchs d'intérêt :

Ce n'est donc pas seulement le mauvais code de l'espace utilisateur et la configuration/les défauts de la distribution qui sont en cause - les anciens noyaux pouvaient mieux gérer cela, et les nouveaux noyaux le font, bien que l'OOM du noyau ne soit toujours pas idéal.

En plus de l'effort pour améliorer l'OOM du noyau, il y a aussi des développements du gestionnaire d'OOM de l'espace utilisateur avec systemd-oomd . Malheureusement, Ubuntu 20.04 LTS ne l'inclut pas car il est publié avec une ancienne version de systemd. Voir Systemd 247 fusionne Systemd-OOMD pour améliorer la gestion de la mémoire faible/hors-mémoire. .

Commentaires sur les options déjà envisagées

  1. Désactiver le swap

Il est recommandé de prévoir au moins une petite partition swap ( Avons-nous vraiment besoin de swap sur les systèmes modernes ? ). La désactivation de l'échange n'empêche pas seulement l'échange des pages inutilisées, mais elle peut également affecter la stratégie heuristique de sur-engagement par défaut du noyau pour l'allocation de la mémoire ( Que signifie l'heuristique dans Overcommit_memory =0 ? ), car cette heuristique tient compte des pages d'échange. Sans échange, l'overcommit peut probablement encore fonctionner dans les modes heuristique (0) ou always (1), mais la combinaison de l'absence d'échange et de la stratégie overcommit never (2) est probablement une mauvaise idée. Ainsi, dans la plupart des cas, l'absence d'échange est susceptible de nuire aux performances.

Par exemple, pensez à un processus qui s'exécute depuis longtemps et qui touche initialement la mémoire pour un travail ponctuel, mais qui ne parvient pas à libérer cette mémoire et continue à fonctionner en arrière-plan. Le noyau devra utiliser la RAM pour cela jusqu'à la fin du processus. Sans swap, le noyau ne peut pas la mettre en page pour quelque chose d'autre qui souhaite utiliser activement la RAM. Pensez aussi au nombre de développeurs qui sont paresseux et ne libèrent pas explicitement la mémoire après utilisation.

  1. définir un ulimit de mémoire maximum

Elle ne s'applique qu'à chaque processus, et il est probablement raisonnable de supposer qu'un processus ne devrait pas demander plus de mémoire que ce que le système possède physiquement ! Il est donc probablement utile d'empêcher un processus fou isolé de déclencher un thrashing tout en étant généreusement défini.

  1. Gardez les programmes importants (X11, bash, kill, top, ...) en mémoire et ne les échangez jamais.

Bonne idée, mais alors ces programmes vont monopoliser la mémoire qu'ils n'utilisent pas activement. Cela peut être acceptable si le programme ne demande qu'une quantité modeste de mémoire.

release de systemd 232 a ajouté quelques options qui rendent cela possible : Je pense que l'on pourrait utiliser 'MemorySwapMax=0' pour empêcher une unité (service) comme ssh d'avoir une partie de sa mémoire échangée.

Néanmoins, il serait préférable de pouvoir donner la priorité à l'accès à la mémoire.

OOM, ulimit et compromis entre intégrité et réactivité

Le "Swap thrashing" (lorsque l'ensemble de la mémoire de travail, c'est-à-dire les pages lues et écrites dans un court laps de temps donné, dépasse la RAM physique) bloquera toujours les E/S de stockage - aucune magie du noyau ne peut sauver un système sans tuer un ou deux processus...

On espérait que les modifications de l'OOM des noyaux Linux plus récents reconnaîtraient que la pression de la mémoire de travail dépasse la mémoire physique, et dans cette situation, identifieraient et tueraient le processus le plus approprié, c'est-à-dire celui qui utilise le plus de mémoire. La mémoire "working set" est la mémoire active/utilisée dont les processus dépendent et à laquelle ils accèdent fréquemment.

L'OOM traditionnel du noyau ne reconnaissait pas la situation dans laquelle l'ensemble de travail dépassait la mémoire physique (RAM), d'où le problème du thrashing. Une grande partition de swap aggravait le problème car il pouvait sembler que le système disposait encore d'une marge de mémoire virtuelle tandis que le noyau dépassait allègrement les commits et coupait plus de demandes de mémoire, pourtant l'ensemble de travail pouvait déborder sur le swap, essayant effectivement de traiter le stockage comme si c'était de la RAM.

Sur les serveurs, l'OOM du noyau semblait accepter la pénalité de performance du thrashing pour un compromis déterminé, lent, ne perdant pas de données. Sur les ordinateurs de bureau, le compromis est différent et les utilisateurs préfèrent un peu de perte de données (sacrifice de processus) pour que les choses restent réactives.

C'était une belle analogie comique sur l'OOM : oom_pardon, aka ne tue pas mon xlock

Incidemment, OOMScoreAdjust est une autre option de systemd pour aider à pondérer et éviter les OOM tuant les processus considérés comme plus importants.

OOMD, maintenant intégré à systemd sous le nom de systemd-oomd, peut déplacer ce problème de l'espace noyau vers l'espace utilisateur.

reprise en mémoire tampon

" Faire en sorte que la réécriture en arrière-plan ne craigne pas L'article de la revue "Page Cache" explique comment le "Page Cache" de Linux (mise en mémoire tampon du stockage en bloc) peut causer certains problèmes lorsque le cache est vidé vers le stockage. Un processus demandant trop de mémoire vive pouvait obliger à libérer de la mémoire dans le cache de pages, ce qui déclenchait une importante réécriture de pages de la mémoire vers le stockage. Une réécriture non limitée aurait une trop grande priorité sur les entrées-sorties et provoquerait une attente d'entrées-sorties (blocage) pour les autres processus. Et si le noyau n'avait plus de cache de page à sacrifier sacrifier, l'échange de la mémoire d'autres processus (plus d'écriture sur le disque) continuerait à se disputer l'entrée-sortie, poursuivant la contention de l'entrée-sortie et privant les autres processus de l'accès au stockage. Ce n'est pas le problème du thrashing en soi, mais il ajoute à la dégradation générale de la réactivité.

Heureusement, avec les nouveaux noyaux, bloc : hook up writeback throttling devrait limiter l'impact de la réécriture du cache de la page sur le stockage. Je suppose que cela s'applique également à l'échange de mémoire du processus de fond vers le stockage.

limitation des ulimits

Un problème avec les ulimits est que la limite de comptabilité s'applique à l'espace d'adresse de la mémoire virtuelle (ce qui implique de combiner l'espace physique et l'espace d'échange). Selon man limits.conf :

       rss
          maximum resident set size (KB) (Ignored in Linux 2.4.30 and
          higher)

Ainsi, définir un ulimit qui s'applique uniquement à l'utilisation de la RAM physique ne semble plus utilisable. D'où

      as
          address space limit (KB)

semble être le seul accordable respecté.

Malheureusement, comme le montre plus en détail l'exemple de WebKit/Gnome, certaines applications ne peuvent pas fonctionner si l'allocation d'espace d'adresse virtuelle est limitée.

les cgroups peuvent aider

Actuellement, il semble lourd, mais possible d'activer certains drapeaux de cgroup du noyau. cgroup_enable=memory swapaccount=1 (par exemple dans Grub config) et ensuite essayer d'utiliser le contrôleur de mémoire cgroup pour limiter l'utilisation de la mémoire.

Les cgroups ont des fonctions de limitation de la mémoire plus avancées que les options 'ulimit'. CGroup v2 Les notes font allusion à des tentatives d'amélioration du fonctionnement des ulimits.

La comptabilisation et la limitation combinées de la mémoire+swap sont remplacées par de véritables contrôle de l'espace d'échange.

Les options du groupe CG peuvent être définies via contrôle des ressources de systemd options. Par exemple :

  • MémoireHigh
  • MemoryMax

D'autres options utiles pourraient être

  • Poids de l'OAI
  • CPUShares

Ceux-ci présentent quelques inconvénients :

  1. Transparent. La documentation de Docker mentionne brièvement 1 % d'utilisation supplémentaire de la mémoire et 10 % de dégradation des performances (probablement en ce qui concerne les opérations d'allocation de mémoire - elle ne le précise pas vraiment).
  2. La partie Cgroup/Systemd a été fortement remaniée il y a un certain temps, donc le flux en amont a impliqué que les vendeurs de distros Linux attendaient que cela se règle d'abord.

En CGroup v2 ils suggèrent que memory.high devrait être une bonne option pour étrangler et gérer l'utilisation de la mémoire par un groupe de processus. Cependant, cette citation de 2015 suggérait que la surveillance des situations de pression mémoire nécessitait plus de travail :

Une mesure de la pression de la mémoire - à quel point la charge de travail est affectée par le manque de mémoire - est nécessaire. en raison d'un manque de mémoire - est nécessaire pour déterminer si une charge de travail a besoin de plus de mémoire ; malheureusement, le mécanisme de surveillance de la pression mémoire n'est pas encore implémenté.

En 2021, il semble que ce travail soit terminé. Voir les références où Facebook a effectué des travaux et des analyses :

Étant donné que les outils de l'espace utilisateur de systemd et cgroup sont complexes, il n'y avait pas de moyen simple de définir quelque chose d'approprié dans le passé et je n'ai donc pas exploité davantage. La documentation sur cgroup et systemd pour Ubuntu n'est pas géniale.

Enfin, les nouvelles éditions de bureau tireront probablement parti de cgroups et de systemd-oomd afin que, en cas de forte pression de la mémoire, le thrashing ne se déclenche pas. Cependant, d'autres travaux futurs pourraient être réalisés pour s'assurer que ssh et les composants du serveur X/gestionnaire de fenêtres obtiennent un accès prioritaire au processeur, à la RAM physique et aux entrées-sorties de stockage, et évitent de concurrencer les processus moins importants. Les fonctionnalités de priorité au CPU et aux E/S du noyau existent depuis un certain temps. Il semble que ce soit l'accès prioritaire à la RAM physique qui faisait défaut, mais cela a été corrigé avec cgroups v2.

Pour Ubuntu 20.04, les priorités CPU et IO ne sont pas du tout définies. Lorsque j'ai vérifié les limites du cgroup systemd, les parts de CPU, etc., pour autant que je puisse dire, Ubuntu 16.04 et maintenant même 20.04 n'a pas intégré de priorités prédéfinies. Par exemple, j'ai exécuté :

systemctl show dev-mapper-Ubuntu\x2dswap.swap

Je l'ai comparé aux mêmes résultats pour ssh, samba, gdm et nginx. Les éléments importants comme l'interface graphique et la console d'administration à distance doivent se battre à armes égales avec tous les autres processus si le thrashing se produit.

J'ai couru :

grep -r MemoryMax /etc/systemd/system /usr/lib/systemd/system/

Et j'ai constaté qu'aucune unité n'applique de limites MemoryMax par défaut pour les fichiers de l'unité. Donc rien n'est limité par défaut et la configuration de la limite de mémoire du cgroup de systemd doit être explicitement configurée par le sysadmin.

Exemple de limites de mémoire que j'ai sur un système de 16 Go de RAM

Je voulais activer l'hibernation, donc j'avais besoin d'une grosse partition d'échange. D'où la tentative d'atténuation avec des ulimits, etc.

ulimit

J'ai mis * hard as 16777216 en /etc/security/limits.d/mem.conf de telle sorte qu'aucun processus ne soit autorisé à demander plus de mémoire que ce qui est physiquement possible. Je n'empêcherai pas le thrashing dans son ensemble, mais sans, un seul processus avec une utilisation avide de la mémoire, ou une fuite de mémoire, peut causer le thrashing. Par exemple, j'ai vu gnome-contacts consomment plus de 8 Go de mémoire lors de tâches banales comme la mise à jour de la liste d'adresses globale d'un serveur Exchange...

Gnome contacts chewing up RAM

Comme vu avec ulimit -S -v En théorie, un processus pourrait demander beaucoup de mémoire mais n'en utiliser activement qu'un sous-ensemble, et fonctionner tranquillement en pensant qu'il a reçu 24 Go de RAM alors que le système n'en a que 16. La limite dure ci-dessus provoquera l'abandon de processus qui auraient pu fonctionner correctement lorsque le noyau refusera leurs demandes de mémoire spéculative gourmandes.

Cependant, il attrape aussi des choses folles comme les contacts gnome et au lieu de perdre la réactivité de mon bureau, j'obtiens une erreur "pas assez de mémoire libre" :

enter image description here

Complications de la mise en place de l'ulimit pour l'espace d'adressage (mémoire virtuelle)

Malheureusement, certains développeurs aiment prétendre que la mémoire virtuelle est une ressource infinie et fixer un ulimit sur la mémoire virtuelle peut casser certaines applications. Par exemple, WebKit (dont dépendent certaines applications de gnome pour l'intégration de contenu web) a ajouté une limite de mémoire virtuelle à la mémoire virtuelle. gigacage de sécurité qui essaie d'allouer des quantités folles de mémoire virtuelle et de FATAL: Could not allocate gigacage memory des erreurs avec un soupçon d'insolence Make sure you have not set a virtual memory limit se produire. La solution de contournement, GIGACAGE_ENABLED=no renonce aux avantages en matière de sécurité, mais de la même manière, ne pas être autorisé à limiter l'allocation de la mémoire virtuelle revient à renoncer à une fonctionnalité de sécurité (par exemple, le contrôle des ressources qui peut empêcher un déni de service). Ironiquement, entre gigacage et les développeurs de gnome, ils semblent oublier que la limitation de l'allocation de mémoire est elle-même un contrôle de sécurité. Et malheureusement, j'ai remarqué que les applications gnome qui s'appuient sur gigacage ne prennent pas la peine de demander explicitement une limite plus élevée, donc même une limite douce casse les choses dans ce cas. D'après Équipe Debian webkit NEWS :

les applications basées sur webkit peuvent ne pas fonctionner si la taille maximale de leur mémoire virtuelle est limitée (par exemple en utilisant ulimit -v)

Pour être juste, si le noyau faisait un meilleur travail pour être capable de refuser l'allocation de mémoire basée sur l'utilisation de la mémoire résidente au lieu de la mémoire virtuelle, alors prétendre que la mémoire virtuelle est illimitée serait moins dangereux.

surengagement

Si vous préférez que les applications se voient refuser l'accès à la mémoire et que vous voulez arrêter le sur-engagement, utilisez les commandes ci-dessous pour tester le comportement de votre système lorsqu'il est soumis à une forte pression mémoire.

Dans mon cas, le rapport commit par défaut était :

$ sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50

Mais elle n'entre pleinement en vigueur que lorsque l'on modifie la politique pour désactiver le surengagement et appliquer le ratio

sudo sysctl -w vm.overcommit_memory=2

Le ratio impliquait que seulement 24 Go de mémoire pouvaient être alloués au total (16 Go de RAM*0,5 + 16 Go de SWAP). Ainsi, je ne verrais probablement jamais d'OOM apparaître, et je serais effectivement moins susceptible d'avoir des processus accédant constamment à la mémoire dans le swap. Mais je sacrifierai probablement aussi l'efficacité globale du système.

Cela provoquera le plantage de nombreuses applications, car il est courant que les développeurs ne gèrent pas de manière élégante le refus par le système d'exploitation d'une demande d'allocation de mémoire. Il s'agit d'un compromis entre le risque occasionnel d'un blocage prolongé dû à un thrashing (perte de tout votre travail après un hard reset) et un risque plus fréquent de plantage de diverses applications. Dans mes tests, cela n'a pas été d'une grande aide car le bureau lui-même s'est planté lorsque le système était sous pression mémoire et qu'il ne pouvait pas allouer de la mémoire. Cependant, au moins les consoles et SSH fonctionnaient toujours.

Comment fonctionne la mémoire de VM overcommit a plus d'informations.

J'ai choisi de revenir à la valeur par défaut pour cela, sudo sysctl -w vm.overcommit_memory=0 Mais il n'en reste pas moins que l'ensemble de la pile graphique du bureau et les applications qu'elle contient se plantent.

Conclusion

  • Le nouveau systemd-oomd devrait améliorer les choses et tuer un processus gourmand avant que la pression de la mémoire physique ne devienne trop élevée.
  • L'OOM traditionnel du noyau ne fonctionnait pas bien parce qu'il n'agissait que si les données physiques de l'ordinateur étaient endommagées. et L'espace mémoire des échanges a été exhumé.
  • Les ulimits et autres moyens de limiter l'overcommit ne fonctionnent pas bien pour les logiciels de bureau parce que de nombreuses applications demandent des espaces mémoire excessivement grands (par exemple les applications utilisant WebKit) ou ne parviennent pas à gérer gracieusement les exceptions de mémoire insuffisante si le noyau refuse une demande de mémoire.

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