Fragmentation de la mémoire Linux

20

Existe-t-il un moyen de détecter la fragmentation de la mémoire sur Linux? En effet, sur certains serveurs de longue durée, j'ai remarqué une dégradation des performances et ce n'est qu'après avoir redémarré le processus que je constate de meilleures performances. Je l'ai remarqué davantage lors de l'utilisation de la prise en charge des pages énormes Linux - les pages énormes dans Linux sont-elles plus sujettes à la fragmentation?

J'ai regardé / proc / buddyinfo en particulier. Je veux savoir s'il existe de meilleures façons (pas seulement les commandes CLI en soi, n'importe quel programme ou contexte théorique) de le regarder.

Raghu
la source
Je ne regarde pas seulement des solutions rapides en ligne de commande, tout programme / théorie simple fera également l'affaire. Par conséquent, je n'ai pas demandé à serverfault.
Raghu
1
Je ne comprends pas un point ici. Autant que je sache, la fragmentation de la mémoire doit entraîner un manque de mémoire et, par conséquent, des erreurs d'allocation de mémoire. Cependant, vous posez des questions sur la dégradation des performances. Est-ce parce que vous avez beaucoup de mémoire échangée sur le disque? Et si oui, qu'est-ce qui donne vmstatsur le terrain so?
@skwllsp - Modification de ma réponse pour être plus précis.
Tim Post
@Raghu - Je ne m'attendrais pas à ce que la plupart des administrateurs système modifient le code du noyau pour que la gestion de la mémoire se comporte différemment, cependant, les administrateurs Linux qualifiés devraient connaître au moins une vue d'ensemble de la façon dont Linux gère la mémoire. Cette question est vraiment en jeu. J'ai voté pour le migrer simplement parce que je ne peux pas suggérer (dans ma réponse) un code qui réponde à votre question. La lecture de / proc ou l'utilisation vmstatest une expérience utilisateur courante. Si vous écriviez un programme pour faire de même, ce serait différent. Si vous avez l'intention d'utiliser bash pour récolter ces informations, modifiez votre question, elle ne sera pas fermée :)
Tim Post
@Tim - Comme je l'ai suggéré, ce n'était pas seulement les commandes bash / cli que je voulais connaître, j'avais besoin des informations pour m'aider dans ma procédure d'analyse comparative (pour analyser les résultats, pas pour les exécuter).
Raghu

Réponses:

12

Je réponds à la balise . Ma réponse n'est spécifique qu'à Linux .

Oui, les pages énormes sont plus sujettes à la fragmentation. Il existe deux vues de la mémoire, celle que votre processus obtient (virtuelle) et celle que le noyau gère (réelle). Plus une page est grande, plus il sera difficile de regrouper (et de la conserver) ses voisins, en particulier lorsque votre service s'exécute sur un système qui doit également prendre en charge d'autres qui, par défaut, allouent et écrivent sur beaucoup plus de mémoire qu'eux finissent par utiliser.

Le mappage par le noyau des adresses accordées (réelles) est privé. Il y a une très bonne raison pour laquelle l'espace utilisateur les voit comme le noyau les présente, car le noyau doit pouvoir surcharger sans confondre l'espace utilisateur. Votre processus obtient une belle, contigu « Disneyfied » espace d'adressage où travailler, sans se soucier de ce que le noyau est en fait en train de faire avec cette mémoire dans les coulisses.

La raison pour laquelle vous constatez une dégradation des performances sur des serveurs de longue durée est probablement due au fait que les blocs alloués qui n'ont pas été explicitement verrouillés (par exemple mlock()/ mlockall()ou posix_madvise()) et non modifiés depuis un certain temps ont été paginés , ce qui signifie que votre service dérape sur le disque lorsqu'il doit lire leur. La modification de ce comportement fait de votre processus un mauvais voisin , c'est pourquoi de nombreuses personnes placent leur SGBDR sur un serveur complètement différent de web / php / python / ruby ​​/ que ce soit. La seule façon d'y remédier, sainement, est de réduire la concurrence pour les blocs contigus.

La fragmentation n'est vraiment perceptible (dans la plupart des cas) que lorsque la page A est en mémoire et que la page B a été déplacée pour être échangée. Naturellement, le redémarrage de votre service semble `` remédier '' à cela, mais uniquement parce que le noyau n'a pas encore eu l'occasion de consulter le processus '' (maintenant) les blocs nouvellement alloués dans les limites de son ratio de surcharge.

En fait, le redémarrage (disons) de 'apache' sous une charge élevée va probablement envoyer des blocs appartenant à d'autres services directement sur le disque. Alors oui, 'apache' s'améliorerait pendant un court laps de temps, mais 'mysql' pourrait souffrir .. au moins jusqu'à ce que le noyau les fasse souffrir également quand il y a simplement un manque de mémoire physique suffisante.

Ajoutez plus de mémoire ou divisez les malloc()consommateurs exigeants :) Ce n'est pas seulement la fragmentation que vous devez regarder.

Essayez vmstatd'obtenir un aperçu de ce qui est réellement stocké où.

Tim Post
la source
Merci pour la réponse. J'utilisais d'énormes pages (taille = 2048 Ko chacune) pour mysql - pool de tampons innodb - pour voir comment cela se passe (en utilisant sysbench). Initialement, lorsque la disponibilité du processus (et même la disponibilité du système) était faible, cela donnait de très bons résultats. Cependant, ses performances ont commencé à se dégrader sur plusieurs séries. En ce qui concerne la page que vous avez mentionnée, j'ai sûrement remarqué une activité élevée de la machine virtuelle, mais je présumais que c'était peut-être à cause du vidage des journaux de référence et innodb (activité vm plus élevée avec des pages énormes que sans). J'ai également défini vm.swappiness sur 1. Je n'ai remarqué aucun changement radical.
Raghu
Selon le manuel fin , "Les pages énormes ne peuvent pas être échangées sous la pression de la mémoire." Je pense que c'est une bonne réponse dans la mémoire standard w / r / t mais pas pour les pages géantes.
Dan Pritts
5

Noyau

Pour obtenir l'utilisation actuelle de l'index de fragmentation:

sudo cat /sys/kernel/debug/extfrag/extfrag_index

Pour défragmenter la mémoire du noyau, essayez d'exécuter:

sysctl vm.compact_memory=1  

Vous essayez également de désactiver Transparent Huge Pages (aka THP) et / ou de désactiver le swap (ou de le diminuer swappiness).

Espace utilisateur

Pour réduire la fragmentation de l'espace utilisateur, vous voudrez peut-être essayer différents allocateurs, par exemple jemalloc(il a de grandes capacités d'introspection , qui vous donneront un aperçu de la fragmentation interne de l'allocateur).

Vous pouvez passer à malloc personnalisé en recompilant votre programme avec lui ou tout simplement en exécutant votre programme avec LD_PRELOAD: LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1 app (méfiez-vous des interactions entre THP et les allocateurs de mémoire )

Bien que légèrement sans rapport avec la fragmentation de la mémoire (mais connecté au compactage / migration de la mémoire), vous souhaiterez probablement exécuter plusieurs instances de votre service, une pour chaque nœud NUMA et les lier à l'aide numactl.

SaveTheRbtz
la source
1
Pourquoi pensez-vous que la désactivation de l'échange pourrait aider? Pour moi, il semble plus probable que la désactivation du swap nuira encore plus.
kasperd
1
Parce qu'il n'y a pas assez d'informations dans le message d'origine, peut-être que le processus fuit et commence à échanger. De plus, je ne vois aucune raison légitime d'utiliser le swap sur à peu près n'importe quel système de production (mb uniquement pour les postes de travail partagés pour les étudiants).
SaveTheRbtz
2
Un espace de swap suffisant améliorera les performances. Les problèmes de performances que vous obtiendrez si l'espace de swap est insuffisant sont une raison suffisante pour activer le swap.
kasperd
1
@SaveTheRbtz Une bonne raison d'utiliser le swap sur un système de production est qu'il donne au système plus d'options qu'il n'utilisera que s'il pense qu'elles sont bénéfiques. En outre, il permet d'éjecter des pages modifiées qui n'ont pas été consultées depuis des heures (et ne peuvent jamais être consultées) de la précieuse mémoire physique. Enfin, il permet au système de gérer sainement les cas où beaucoup plus de mémoire est réservée que celle utilisée.
David Schwartz
2
"seulement s'il pense qu'ils sont bénéfiques" - cela ajoute une heuristique supplémentaire et rend le système moins prévisible. Les algorithmes de remplacement de page (utilisés en swap et anonymes mmap) sont également implémentés différemment sur différents noyaux (par exemple Linux vs FreeBSD), ou même sur différentes versions du même système d'exploitation (2.6.32 vs 3.2 vs 3.10) .. "il autorise les pages modifiées [. ..] à éjecter de la [...] mémoire physique "- qui masquera les fuites de mémoire. "gérer les cas où beaucoup plus de mémoire est réservée que celle utilisée" - un système lent est bien pire qu'un système en panne, donc "sain" est discutable.
SaveTheRbtz
4

L'utilisation de pages volumineuses ne devrait pas entraîner de fragmentation supplémentaire de la mémoire sous Linux; Le support Linux pour les pages volumineuses est uniquement pour la mémoire partagée (via shmget ou mmap), et toutes les pages volumineuses utilisées doivent être spécifiquement demandées et préallouées par un administrateur système. Une fois en mémoire, ils y sont épinglés et ne sont pas échangés. Le défi de l'échange de pages énormes face à la fragmentation de la mémoire est exactement la raison pour laquelle elles restent épinglées en mémoire (lors de l'allocation d'une énorme page de 2 Mo, le noyau doit trouver 512 pages 4KB libres contiguës, qui n'existent peut-être même pas).

Documentation Linux sur d'énormes pages: http://lwn.net/Articles/375098/

Il existe une circonstance où la fragmentation de la mémoire peut ralentir l'allocation de pages volumineuses (mais pas là où les pages volumineuses provoquent la fragmentation de la mémoire), et c'est si votre système est configuré pour augmenter le pool de pages volumineuses à la demande d'une application. Si / proc / sys / vm / nr_overcommit_hugepages est supérieur à / proc / sys / vm / nr_hugepages, cela peut se produire.

jstultz
la source
En effet - et cela devrait généralement aider les performances car cela empêchera les échecs TLB (voir l'article lié pour des explications).
Dan Pritts
0

Il y en a /proc/buddyinfoqui est très utile. C'est plus utile avec un bon format de sortie, comme ce script Python peut le faire:

https://gist.github.com/labeneator/9574294

Pour les pages volumineuses, vous voulez des fragments gratuits au format 2097152 (2 Mo) ou plus. Pour les pages volumineuses transparentes, il se compactera automatiquement lorsque le noyau en sera demandé, mais si vous voulez voir combien vous pouvez en obtenir, alors en tant que root:

echo 1 | sudo tee /proc/sys/vm/compact_memory

De plus, les pages énormes causent de gros problèmes de fragmentation. Soit vous ne pouvez pas obtenir de pages volumineuses, soit leur présence oblige le noyau à passer beaucoup de temps supplémentaire à essayer d'en obtenir.

J'ai une solution qui fonctionne pour moi. Je l'utilise sur quelques serveurs et mon ordinateur portable. Cela fonctionne très bien pour les machines virtuelles.

Ajoutez l' kernelcore=4Goption à votre ligne de commande du noyau Linux. Sur mon serveur, j'utilise la 8G. Soyez prudent avec le nombre, car cela empêchera votre noyau d'allouer quoi que ce soit en dehors de cette mémoire. Les serveurs qui ont besoin de beaucoup de tampons de socket ou qui écrivent des disques sur des centaines de lecteurs n'aimeront pas être limités comme ça. Toute allocation de mémoire qui doit être «épinglée» pour la dalle ou le DMA appartient à cette catégorie.

Toute votre autre mémoire devient alors "mobile", ce qui signifie qu'elle peut être compactée en jolis morceaux pour une allocation de page énorme. Désormais, les pages immenses et transparentes peuvent vraiment décoller et fonctionner comme elles sont censées le faire. Chaque fois que le noyau a besoin de plus de 2 millions de pages, il peut simplement remapper des pages 4K à un autre endroit.

Et, je ne suis pas totalement sûr de la façon dont cela interagit avec les E / S directes sans copie. La mémoire dans la "zone mobile" n'est pas censée être épinglée, mais une demande d'E / S directe ferait exactement cela pour le DMA. Il pourrait le copier. Il pourrait de toute façon le coincer dans la zone mobile. Dans les deux cas, ce n'est probablement pas exactement ce que vous vouliez.

Zan Lynx
la source