En tant qu’utilisateur averti et administrateur de serveurs sous Linux, je m’intéresse à la gestion que mon OS fait de la mémoire. Certes, le prix de la RAM au Go tend à baisser au fur et à mesure des nouvelles normes DDR, mais je tiens à vérifier que chaque octet de mémoire est bien mis à profil pour accélérer mes applications et optimiser le système. C’est bien là un des avantages d’un OS open-source, la transparence et la configurabilité à souhait.
L’utilisation mémoire sous Linux
Linux ate my RAM ?
Une erreur communément commise par les utilisateurs Linux est de croire que plus vous avez de mémoire disponible, meilleur cela est. En effet, la philosophie de Linux de chercher à consommer le maximum de mémoire afin de tirer le meilleur parti possible des ressources qui lui sont mises à disposition. Avec la commande free on a un aperçu de cela.
1 2 3 4 5 |
root@ordinateur:~# free -m total used free shared buffers cached Mem: 32074 7402 24671 31 452 4905 -/+ buffers/cache: 2044 30029 Swap: 0 0 0 |
La mémoire used concerne l’ensemble de la mémoire consommée par tous les usages possibles du système d’exploitation. Sous Linux on a :
- La mémoire réclamée par les programmes qui s’exécutent, dont l’OS. (Ici 2044 Mo)
- La mémoire de cache de fichiers (Ici 4905 Mo)
- La mémoire de buffers IO (Ici 452 Mo)
La mémoire consommée par les programmes dépend de l’état de charge du système, mais l’OS a une grande marge de manœuvre pour stocker un maximum de cache et de buffer en mémoire afin d’accélérer le lancement des applications et le chargement des fichiers. Mais pas de panique, en termes d’allocation mémoire, les programmes seront toujours largement prioritaires sur les autres usages.
Ainsi, optimiser l’usage mémoire sous Linux ne consiste pas à libérer de la mémoire, mais plutôt d’en consommer le plus possible pour améliorer ses propres scénarios d’utilisation.
Le « Linux ate my RAM » est une vraie institution parmi les administrateurs système pour désigner cette mécompréhension du débutant. Pour en savoir plus, je vous invite à lire mon article sur le cache des fichiers sous linux.
Quand il n’y a plus de RAM, il y a le swap
Depuis toujours, les OS prévoient un fichier d’échange ou une partition d’échange, dite de « swap » qui sera utilisée comme de la mémoire lorsque les barrettes de RAM seront remplies à 100% alors que les programmes en demandent encore plus.
C’est mieux que rien et cela évite le plantage ou l’arrêt brusque d’applications pour manque de mémoire (Out of memory, process killed) mais l’utilisation de swap est extrêmement pénalisante en raison de la lenteur du disque dur par rapport à la mémoire. De plus, les mécanismes du noyau pour utiliser un périphérique externe en tant qu’espace mémoire sont beaucoup plus compliqués et plus lents que l’utilisation de mémoire directement. Utiliser le swap est déjà un échec en soi, une action parfaitement dispensable étant donné le faible coût de la mémoire.
Ce qui est tout de même pratique, c’est que Linux nous autorise à configurer sa propension à consommer du swap par rapport à la mémoire. Cela se joue dans le paramètre vm.swappiness dans /etc/sysctl.conf . Si se paramètre est défini à zéro, le swap est désactivé (sauf cas extrême) et à ce moment-là autant ne pas allouer une partition ou un fichier de swap ! Sa valeur maximum est 100, elle implique que tous les échanges mémoire se font en swap. Sur les valeurs intermédiaires, un vm.swappiness de 30 implique que le swap commence à être utilisé à partir du moment où 30% de la mémoire reste libre (70% occupée). La valeur par défaut de Linux est vm.swappiness = 60, le noyau va donc commencer à swapper dès 40% d’utilisation mémoire.
Aujourd’hui l’usage du swap n’est plus uniquement d’utiliser un disque dur comme espace mémoire, on peut s’en servir dans différents cas de figure.
- Utiliser un SSD ou un SSD SLC typé « cache » très rapide pour faire comme de la mémoire (toujours plus lent).
- Utiliser un périphérique spécial en mémoire permettant la compression (voir zRam)
Les espaces d’échange sont visibles par la commande swapon -s, on voit alors le nom des partitions (ou des fichiers) leur taille, leur usage ainsi que leur priorité d’utilisation par rapport aux autres. Le fin du fin si vous voulez utiliser du swap, c’est de définir une priorité identique entre différents périphériques afin de swapper en parallèle et donc d’accroître un peu les performances en répartissant la charge.
Les techniques pour agrandir la mémoire allouable
La compression avec zRam
De même qu’on peut économiser de l’espace disque en compressant un fichier (avec zip, 7zip, xz etc), on peut demander au système d’exploitation de compresser les données stockées en mémoire pour économiser de la place pour d’autres opérations. Dit autrement, cela revient à échanger un peu de temps CPU pour économiser quelques Mo de RAM. Ces derniers temps la puissance CPU a tellement augmenté pour atteindre de très hauts niveaux de performance que l’opération est rentable.
Sous Linux le logiciel permettant cette opération est zRam. Sous Ubuntu il suffit d’installer zram-config pour que le système de compression s’active automatiquement.
On doit constater que le module noyau zram est chargé. En réalité la totalité de la mémoire n’est pas compressée mais seulement des portions qui sont accédées par des devices /dev/zram* que l’on peut voir avec swapon -s :
1 2 3 4 5 6 |
root@ordinateur:~# swapon -s Filename Type Size Used Priority /dev/zram0 partition 957500 0 5 /dev/zram1 partition 957500 0 5 /dev/zram2 partition 957500 0 5 /dev/zram3 partition 957500 0 5 |
On constate donc que zRam consiste à créer des partitions de swap qui ont la particularité d’être compressées et contenues en mémoire, contrairement aux partitions de swap standard qui sont sur le disque dur. Pourquoi quatre partitions plutôt qu’une ? Pour multi-threader, pardi !
Ainsi le système zRam ne peut fonctionner que lorsque la RAM est remplie selon un taux défini par le paramètre vm.swappiness (par défaut dès 40% d’occupation RAM).
Cette forme de compression de la mémoire est une sorte de surcouche qui peut fonctionner avec n’importe quel logiciel. Comme toute compression, cela consomme du CPU et zRam doit par conséquent fonctionner sur des ordinateurs généreusement lotis en processeur. De plus, il ne faut pas oublier que le mécanisme du swap est plus lent que l’allocation direct de mémoire vive, en raison d’une complexité plus grande qui est gérée par le noyau.
L’utilisation de zRam ne peut pas rendre un ordinateur plus rapide, mais simplement lui permettre d’encaisser plus de données en mémoire au prix d’une consommation CPU. C’est donc une « optimisation » à réfléchir par deux fois.
Pour plus d’informations sur zRam, voir sur le site du noyau Linux.
La compression avec zvol
Théoriquement avec ZFS, on pourrait utiliser un volume zvol compressé, qui est un périphérique de blocs, en tant que swap. C’est une application très intéressante d’une fonctionnalité de base de ZFS, notamment pour mettre en place la compression. Voir ici la procédure. Je dis bien théoriquement, parce que la stabilité de ZFS sous Linux n’est pas garantie pour ce type d’applications. Je n’ai moi-même jamais testé cette configuration.
Pour continuer dans la théorie, on pourrait alors facilement snapshoter le volume contenant la partition swap pour un usage extérieur du type débogage ou hacking. Cette possibilité de snapshoter un swap est vraiment très dangereuse. Elle peut néanmoins avoir son utilité « en laboratoire ».
Plus choquant encore, on pourrait potentiellement dédupliquer un swap avec un volume ZFS. Les performances seraient très certainement épouvantables. C’est un cas d’usage inutile qui ne devrait jamais passer en pratique. Pourquoi ? Pour fonctionner, la déduplication ZFS a besoin de CPU et de… mémoire !
La déduplication de pages mémoire avec KSM
KSM est l’acronyme de Kernel Samepage Merging, ce qui signifie littéralement fusion de pages similaires par le noyau. En gros, le noyau Linux analyse la mémoire consommée et fusionne les données identiques qui sont stockées en mémoire. Lorsque vous avez plusieurs instances du même logiciel, il est très courant que la mémoire soit utilisée pour stocker plusieurs fois la même chose. Grâce à KSM, c’est de l’histoire ancienne.
Ce système ne fonctionne pas sur tous les logiciels, ceux-ci doivent en effet être prévus pour lors de leur développement en faisant appel à la primitive système madvise pour réclamer de la mémoire.
Voici la commande pour vérifier que KSM est bien activé sur l’ordinateur.
1 2 |
root@ordinateur:~# cat /sys/kernel/mm/ksm/run 1 |
Le retour indique 0 pour désactivé et 1 pour activé. S’il n’est pas activé par défaut, on peut lancer la commande suivante, ou l’inclure dans /etc/rc.local.
1 |
root@ordinateur:~# echo 1 > /sys/kernel/mm/ksm/run |
Enfin, pour afficher des statistiques sur l’utilisation et l’efficacité du système. Les explications sont présentes sur la page de siphos.be.
1 2 3 4 5 6 |
root@ordinateur:~# grep -H '' /sys/kernel/mm/ksm/pages_* /sys/kernel/mm/ksm/pages_shared:156 /sys/kernel/mm/ksm/pages_sharing:17472 /sys/kernel/mm/ksm/pages_to_scan:100 /sys/kernel/mm/ksm/pages_unshared:26672 /sys/kernel/mm/ksm/pages_volatile:116 |
Cet exemple d’output a été obtenu sur une machine Debian qui fait tourner une machine virtuelle sous Debian également. Ce n’est qu’en démarrant la machine virtuelle que j’ai constaté des pages partagées. Vraisemblablement KSM a réussi à mutualiser la RAM entre l’hyperviseur et le système hôte, c’est très fort. Dans un autre cas de figure d’un hyperviseur faisant tourner 6 machines virtuelles, j’ai pu économiser 13 Go de mémoire, ce n’est pas rien. J’attribue cette performance au fait que les machines virtuelles ont beaucoup de mémoire allouée qui n’est pas consommée, donc c’est facile pour KSM de dédupliquer.
La signification de ces lignes est donnée dans le manuel du noyau, notamment :
- pages_shared : pages mémoires qui ont pu être partagées grâce au drapeau MADV_MERGEABLE spécifié par le développeur du logiciel.
- pages_unshared : pages mémoires avec le drapeau MADV_MERGEABLE mais qui ne sont pas partagées par manque de double usage.
- pages_sharing : pages mémoires économisées grâce au partage des pages_shared.
- pages_volatile : pages mémoires qui bougent trop souvent pour être partagées.
Pour rappel, une page mémoire fait souvent 4096 octets, on peut le confirmer avec la commande getconf PAGESIZE .
KSM est réputé pour fonctionner bien avec l’hyperviseur KVM sous Linux. Cela devient alors très similaire aux technologies VMWare TPS (Transparent Page Sharing) et Xen Memory CoW. A noter que si KSM tourne sur le système hôte, il n’y a pas de gain à espérer en le faisant tourner sur le système invité, le principe de base de la déduplication étant que pour dédupliquer… il faut un maximum de données pour en trouver qui soit déduplicable.
Ce système consiste finalement à scanner perpétuellement la mémoire à la recherche de pages à fusionner, cela fait travailler le processeur et la mémoire. Je n’ai pas cherché à comparer le coût CPU par rapport à zRam mais il devrait théoriquement être inférieur.
Contrairement à zRam, KSM est en mesure de réduire l’utilisation mémoire dès les premiers octets consommés. On pourrait être tenté de faire tourner zRam et KSM ensemble, rien ne s’oppose à ce fonctionnement mais KSM ne travaillera que sur les portions de mémoire non compressées, et en aucun cas sur les partitions de swap, et cela qu’elles soient stockées sur le disque dur ou sur une partition zram.
Utiliser la mémoire en tant que cache de fichiers
Je traite cette problématique dans mon article sur le cache de fichiers Linux. En réalité, Linux fait déjà tout ce qu’il faut pour accélérer la lecture des fichiers à l’aide du cache en mémoire, mais jamais au détriment des processus. Dans un fonctionnement « de croisière » il n’y aura donc presque rien à gagner. Lors du boot du système c’est une autre histoire : et il existe des optimisations possibles avec le cache (cf. lien ci-dessus).
Ce qui peut être très intéressant, c’est de savoir quel fichier est en cache, et quel fichier ne l’est pas pour comprendre les performances.
Tests matériels de la mémoire
Memtest86
Cet outil est bien connu et il a l’avantage de tester l’intégralité de la mémoire à la recherche d’erreurs matérielles pouvant affecter la stabilité de l’ordinateur. Son inconvénient est que l’on doit booter dessus ce qui empêche l’utilisation de l’ordinateur. Memtest est proposé sur le CD d’Ubuntu, sur le Live CD UBCD ou encore sur Debian et Ubuntu en tant que paquet qui configure Grub pour proposer Memtest lors du démarrage.
Memtester
Il s’agit là d’un logiciel que l’on fait tourner sous Linux. On peut ainsi tester toute la mémoire qui n’a pas encore été consommée par l’OS ou d’autres programmes. Exemple pour tester une zone de 1M une seule fois. En pratique, on cherchera à tester la plus grande portion possible, sans jamais pouvoir tester 100% de la mémoire à cause de l’occupation du noyau et des processus en cours.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
root@ordinateur:~# memtester 1M 1 memtester version 4.3.0 (64-bit) Copyright (C) 2001-2012 Charles Cazabon. Licensed under the GNU General Public License version 2 (only). pagesize is 4096 pagesizemask is 0xfffffffffffff000 want 1MB (1048576 bytes) got 1MB (1048576 bytes), trying mlock ...locked. Loop 1/1: Stuck Address : ok Random Value : ok Compare XOR : ok Compare SUB : ok Compare MUL : ok Compare DIV : ok Compare OR : ok Compare AND : ok Sequential Increment: ok Solid Bits : ok Block Sequential : ok Checkerboard : ok Bit Spread : ok Bit Flip : ok Walking Ones : ok Walking Zeroes : ok 8-bit Writes : ok 16-bit Writes : ok Done. |
Très intéressant.
Cependant, j’ai un problème bizarre car j’ai un PC avec 64 Gb de RAM ( debian 10 ) sur lequel tourne 3 VM.
J’avais prévu 16 Gb par machine soit 48 Gb et le reste pour le système ( avec ZFS ).
Cependant, si je ne démarre pas les VM immédiatement, la mémoire disponible devient insuffisante et pratiquement l’entièreté de la mémoire est utilisée.
Avez-vous une idée, une piste.
ZFS consomme de la mémoire et elle est affichée en vert dans htop. Cette mémoire n’est pas libérée automatiquement par le noyau en cas de besoin de mémoire par un autre processus, comme ce serait le cas avec la conso représentée en bleu (buffers IO) ou en jaune (cache de fichiers Linux).
Par conséquent vous devrez limiter l’allocation mémoire de ZFS. Apparemment il y a une option « zfs zfs_arc_max » à passer au module zfs lors de son chargement (source).
Par ailleurs, l’utilisation de ZFS avec la virtualisation est tentante. Mais vous devez savoir que l’utilisation de zvol comme périphériques mode bloc pour les VM ne permettra pas aux VM de se suspendre en cas d’espace disque faible sur l’hyperviseur. De quoi déconseiller les allocations sparse pour ces applications.