GNU/Linux >> Tutoriels Linux >  >> Linux

Situation Linux oom (noyau 32 bits)

Solution 1 :

Une approche "coup de marteau" consisterait cependant à passer à un système d'exploitation 64 bits (c'est-à-dire 32 bits) car la disposition des zones est différente.

OK, alors ici, je vais tenter de répondre pourquoi vous avez vécu un OOM ici. Il y a un certain nombre de facteurs en jeu ici.

  • La taille de la commande de la requête et la façon dont le noyau traite certaines tailles de commande.
  • La zone sélectionnée.
  • Les filigranes utilisés par cette zone.
  • Fragmentation dans la zone.

Si vous regardez le MOO lui-même, il y a clairement beaucoup de mémoire disponible mais OOM-killer a été invoqué ? Pourquoi ?

La taille de la commande de la requête et la manière dont le noyau traite certaines tailles de commande

Le noyau alloue de la mémoire par ordre. Une « commande » est une région de RAM contiguë qui doit être satisfaite pour que la requête fonctionne. Les ordres sont classés par ordre de grandeur (d'où le nom ordre) à l'aide de l'algorithme 2^(ORDER + 12) . Ainsi, l'ordre 0 est 4096, l'ordre 1 est 8192, l'ordre 2 est 16384 et ainsi de suite.

Le noyau a une valeur codée en dur de ce qui est considéré comme un "ordre élevé" (> PAGE_ALLOC_COSTLY_ORDER ). Il s'agit de l'ordre 4 et supérieur (64 Ko ou plus est un ordre élevé).

Les commandes élevées sont satisfaites pour les allocations de pages différemment des commandes faibles. Une allocation d'ordre élevé si elle ne parvient pas à saisir la mémoire, sur les noyaux modernes le fera.

  • Essayez d'exécuter la routine de compactage de la mémoire pour défragmenter la mémoire.
  • Jamais appelez OOM-killer pour satisfaire la demande.

La taille de votre commande est indiquée ici

Dec 27 09:19:05 2013 kernel: : [277622.359064] squid invoked oom-killer: gfp_mask=0x42d0, order=3, oom_score_adj=0

L'ordre 3 est le plus élevé des demandes d'ordre inférieur et (comme vous le voyez) invoque OOM-killer pour tenter de le satisfaire.

Notez que la plupart des allocations d'espace utilisateur n'utilisent pas de requêtes d'ordre élevé. Généralement, c'est le noyau qui nécessite des régions de mémoire contiguës. Une exception à cela peut être lorsque l'espace utilisateur utilise des pages énormes - mais ce n'est pas le cas ici.

Dans votre cas, l'allocation d'ordre 3 est appelée par le noyau qui souhaite mettre un paquet en file d'attente dans la pile réseau - nécessitant une allocation de 32 Ko pour ce faire.

La zone sélectionnée.

Le noyau divise vos régions de mémoire en zones. Ce découpage est effectué car sur x86, certaines régions de la mémoire ne sont adressables que par certains matériels. Un matériel plus ancien peut uniquement être en mesure d'adresser la mémoire dans la zone 'DMA' par exemple. Lorsque nous voulons allouer de la mémoire, nous choisissons d'abord une zone et seulement la mémoire libre de cette zone est prise en compte lors de la prise de décision d'allocation.

Bien que je ne sois pas complètement au courant de l'algorithme de sélection de zone, le cas d'utilisation typique n'est jamais d'allouer à partir de DMA, mais de sélectionner généralement la zone adressable la plus basse qui pourrait satisfaire la demande.

De nombreuses informations de zone sont crachées pendant OOM qui peuvent également être glanées à partir de /proc/zoneinfo .

Dec 27 09:19:05 2013 kernel: : [277622.359382] DMA free:2332kB min:36kB low:44kB high:52kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15968kB managed:6960kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:8kB slab_unreclaimable:288kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes
Dec 27 09:19:05 2013 kernel: : [277622.359393] Normal free:114488kB min:3044kB low:3804kB high:4564kB active_anon:0kB inactive_anon:0kB active_file:252kB inactive_file:256kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:894968kB managed:587540kB mlocked:0kB dirty:0kB writeback:0kB mapped:4kB shmem:0kB slab_reclaimable:117712kB slab_unreclaimable:138616kB kernel_stack:11976kB pagetables:0kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:982 all_unreclaimable? yes
Dec 27 09:19:05 2013 kernel: : [277622.359404] HighMem free:27530668kB min:512kB low:48272kB high:96036kB active_anon:2634060kB inactive_anon:217596kB active_file:4688452kB inactive_file:1294168kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:36828872kB managed:36828872kB mlocked:0kB dirty:0kB writeback:0kB mapped:183132kB shmem:39400kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:430856kB unstable:0kB bounce:367564104kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no

Les zones que vous avez, DMA, Normal et HighMem indiquent une plate-forme 32 bits, car la zone HighMem est inexistante sur 64 bits. Également sur les systèmes 64 bits, Normal est mappé à 4 Go et au-delà, tandis que sur 32 bits, il mappe jusqu'à 896 Mo (bien que, dans votre cas, le noyau ne gère qu'une partie plus petite que celle-ci :- managed:587540kB .)

Il est possible de dire d'où vient cette allocation en regardant à nouveau la première ligne, gfp_mask=0x42d0 nous dit quel type d'allocation a été fait. Le dernier octet (0) nous indique qu'il s'agit d'une allocation depuis la zone normale. Les significations de gfp se trouvent dans include/linux/gfp.h.

Les filigranes utilisés par cette zone.

Lorsque la mémoire est faible, les actions pour la récupérer sont spécifiées par le filigrane. Ils s'affichent ici :min:3044kB low:3804kB high:4564kB . Si la mémoire libre atteint 'bas', alors l'échange aura lieu jusqu'à ce que nous passions le seuil 'haut'. Si la mémoire atteint 'min', nous devons tuer des éléments afin de libérer de la mémoire via le OOM-killer.

Fragmentation dans la zone.

Afin de voir si une requête pour une commande spécifique de mémoire peut être satisfaite, le noyau comptabilise le nombre de pages libres et disponibles de chaque commande. Ceci est lisible en /proc/buddyinfo . Les rapports OOM-killer crachent également les informations sur les amis, comme on le voit ici :

Normal: 5360*4kB (UEM) 3667*8kB (UEM) 3964*16kB (UEMR) 13*32kB (MR) 0*64kB 1*128kB (R) 1*256kB (R) 0*512kB 0*1024kB 0*2048kB 0*4096kB = 115000kB

Pour qu'une allocation de mémoire soit satisfaite, il doit être de la mémoire libre disponible dans la taille de commande demandée ou une allocation supérieure. Avoir beaucoup, beaucoup de données gratuites dans les ordres inférieurs et aucune dans les ordres supérieurs signifie que votre mémoire est fragmentée. Si vous obtenez une allocation d'ordre très élevé, il est possible (même avec beaucoup de mémoire libre) qu'elle ne soit pas satisfaite car il n'y a pas de pages d'ordre élevé disponibles. Le noyau peut défragmenter la mémoire (c'est ce qu'on appelle le compactage de la mémoire) en déplaçant de nombreuses pages de bas niveau afin qu'elles ne laissent pas de vides dans l'espace RAM adressable.

OOM-killer a été invoqué ? Pourquoi ?

Donc, si nous tenons compte de ces éléments, nous pouvons dire ce qui suit :

  • Une allocation contiguë de 32 Ko a été tentée. De la zone normale.
  • Il y avait suffisamment de mémoire libre dans la zone sélectionnée.
  • Il y avait de la mémoire disponible pour les ordres 3, 5 et 6 13*32kB (MR) 1*128kB (R) 1*256kB (R)

Donc, s'il y avait mémoire libre, d'autres commandes pourraient satisfaire la demande. que s'est-il passé ?

Eh bien, l'allocation à partir d'une commande ne se limite pas à vérifier la quantité de mémoire libre disponible pour cette commande ou plus. Le noyau soustrait effectivement la mémoire de tous les ordres inférieurs de la ligne libre totale, puis effectue la vérification du filigrane min sur ce qui reste.

Ce qui se passe dans votre cas, c'est de vérifier notre mémoire libre pour cette zone que nous devons faire.

115000 - (5360*4) - (3667*8) - (3964*16) = 800

Cette quantité de mémoire libre est vérifiée par rapport au min filigrane, qui est 3044. Ainsi, techniquement parlant, vous n'avez plus de mémoire libre pour effectuer l'allocation que vous avez demandée. Et c'est pourquoi vous avez invoqué OOM-killer.

Correction

Il y a deux correctifs. La mise à niveau vers 64 bits modifie votre partitionnement de zone de sorte que "Normal" soit de 4 Go à 36 Go, de sorte que vous ne finirez pas par "définir par défaut" votre allocation de mémoire dans une zone qui peut être si fortement fragmentée. Ce n'est pas que vous ayez plus de mémoire adressable qui résout ce problème (parce que vous utilisez déjà PAE), mais simplement que la zone à partir de laquelle vous sélectionnez a plus de mémoire adressable.

La deuxième méthode (que je n'ai jamais testée) est d'essayer de faire en sorte que le noyau compacte votre mémoire de manière plus agressive.

Si vous modifiez la valeur de vm.extfrag_threshold de 500 à 100, il est plus probable de compacter la mémoire dans le but d'honorer une allocation d'ordre élevé. Bien que je n'ai jamais joué avec cette valeur auparavant - cela dépendra également de votre index de fragmentation disponible dans /sys/kernel/debug/extfrag/extfrag_index . Je n'ai pas de boîte pour le moment avec un noyau suffisamment nouveau pour voir ce que cela offre de plus que cela.

Alternativement, vous pouvez exécuter une sorte de tâche cron (c'est horriblement, horriblement moche) pour compacter manuellement vous-même la mémoire en écrivant dans /proc/sys/vm/compact_memory .

Honnêtement, je ne pense pas qu'il existe vraiment un moyen de régler le système pour éviter ce problème - c'est la nature de l'allocateur de mémoire de fonctionner de cette façon. Changer l'architecture de la plate-forme que vous utilisez est probablement la seule solution fondamentalement résolue.

Solution 2 :

Dès le départ :vous devriez vraiment optez pour un système d'exploitation 64 bits. Avez-vous une bonne raison de rester en 32 bits ici ?

Il est difficile de diagnostiquer ce problème sans examiner le système de plus près, de préférence au moment où il échoue, donc mon message (rapide) est plus ou moins génériquement destiné aux problèmes de mémoire sur les systèmes 32 bits. Ai-je mentionné que le passage au 64 bits ferait disparaître tout cela ?

Votre problème est triple.

Tout d'abord, même sur un noyau PAE, l'espace d'adressage par processus est limité à 4 Go[1]. Cela signifie que votre instance squid ne pourra jamais consommer plus de 4 Go de RAM par processus. Je ne connais pas très bien squid, mais s'il s'agit de votre serveur proxy principal, cela pourrait ne pas suffire de toute façon.

Deuxièmement, sur un système 32 bits avec de grandes quantités de RAM, une grande quantité de mémoire dans ce qu'on appelle 'ZONE_NORMAL' est utilisée pour stocker les structures de données nécessaires pour utiliser la mémoire dans ZONE_HIGHMEM. Ces structures de données ne peuvent pas être déplacées dans ZONE_HIGHMEM elles-mêmes, car la mémoire que le noyau utilise à ses propres fins doit toujours être dans ZONE_NORMAL (c'est-à-dire dans le premier 1GiB-ish). Plus vous avez de mémoire dans ZONE_HIGHMEM (beaucoup, dans votre cas), plus cela devient un problème, car le noyau a alors besoin de plus en plus de mémoire de ZONE_NORMAL pour gérer ZONE_HIGHMEM. Au fur et à mesure que la quantité de mémoire libre dans ZONE_NORMAL s'épuise, votre système peut échouer à certaines tâches, car ZONE_NORMAL est l'endroit où un lot de choses se passe sur un système 32 bits. Toutes les opérations de mémoire liées au noyau, par exemple;)

Troisièmement, même s'il reste de la mémoire dans ZONE_NORMAL (je n'ai pas parcouru vos journaux en détail), certaines opérations de mémoire nécessiteront de la mémoire non fragmentée. Par exemple, si toute votre mémoire est fragmentée en très petits morceaux, certaines opérations qui nécessitent plus que cela échoueront. [3] Un bref examen de vos journaux montre une quantité assez importante de fragmentation dans ZONE_DMA et ZONE_NORMAL.

Edit :la réponse de Mlfe ci-dessus contient une excellente explication de la façon dont cela fonctionne en détail.

Encore une fois :sur un système 64 bits, toute la mémoire est dans ZONE_NORMAL. Il n'y a pas de zone HIGHMEM sur les systèmes 64 bits. Problème résolu.

Edit :Vous pouvez jeter un œil ici [4] pour voir si vous pouvez dire à oom-killer de laisser vos processus importants tranquilles. Cela ne résoudra pas tout (le cas échéant), mais cela vaut peut-être la peine d'essayer.

[1] http://en.wikipedia.org/wiki/Physical_address_extension#Design

[2] http://www.redhat.com/archives/rhelv5-list/2008-September/msg00237.html et https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/5/html /Tuning_and_Optimizing_Red_Hat_Enterprise_Linux_for_Oracle_9i_and_10g_Databases/sect-Oracle_9i_and_10g_Tuning_Guide-Hardware_Architectures_and_Linux_Kernels-a32_bit_Architecture_and_the_hugemem_Kernel.html

[3] http://bl0rg.krunch.be/oom-frag.html

[4] http://lwn.net/Articles/317814/

Solution 3 :

@MIfe a déjà fourni une excellente rédaction sur la façon dont les allocations de mémoire dans le noyau sont gérées et vous a également fourni une solution appropriée comme le passage à un système d'exploitation 64 bits et un piratage désagréable comme le compactage manuel de la mémoire via /proc/sys/vm/compact_memory en cron .

Mes 2 cents seraient une autre solution de contournement qui pourrait vous aider :
J'ai remarqué que vous avez tcp_tso_segment dans votre backtrace du noyau, faites ainsi :

# ethtool -K ethX tso off gso off lro off

peut diminuer la pression sur mm en le forçant à utiliser des ordres inférieurs.

PS . la liste de tous les déchargements peut être obtenue via # ethtool -k ethX

Solution 4 :

La panique est due au fait que le sysctl "vm.panic_on_oom =1" est défini - l'idée est que le redémarrage du système le ramène à un état sain. Vous pouvez modifier cela dans sysctl.conf.

Tout en haut, nous lisons calmar invoqué oom tueur. Vous pouvez vérifier votre configuration squid et son utilisation maximale de la mémoire (ou simplement passer à un système d'exploitation 64 bits).

/proc/meminfo affiche une zone de mémoire élevée en cours d'utilisation, vous exécutez donc un noyau 32 bits avec 36 Go de mémoire. Vous pouvez également voir que dans la zone normale, afin de répondre à la demande de mémoire de squid, le noyau a scanné 982 pages sans succès :

pages_scanned:982 all_unreclaimable? yes

Linux
  1. Le cycle de vie des tests du noyau Linux

  2. Comment mettre à niveau le noyau sur Linux Desktop

  3. Noyau Linux pour Nintendo Wii ?

  4. Comment le noyau Linux détermine-t-il l'ordre des appels __init ?

  5. Comment savoir si mon noyau Linux fonctionne en 32 bits ou 64 bits ?

Linux est-il un système d'exploitation ou un noyau ?

Le noyau Linux contre. Mac noyau

Le noyau Linux et ses fonctions

Que faire en cas de panique du noyau Linux

Guide complet de journalisation Linux

Linux - Schéma du noyau Linux Vs. Outils de performances ?