Prise en charge NUMA et pinning CPU pour les serveurs dédiés
16 min de lecture - 16 juin 2026

Comment inspecter la topologie NUMA et affecter les charges de travail Linux aux cœurs et à la mémoire appropriés. Couvre numactl, taskset, systemd, les paramètres du BIOS et les stratégies spécifiques aux charges de travail.
Prise en charge NUMA et pinning CPU pour les serveurs dédiés
Sur tout serveur multi-sockets, l'endroit où un processus s'exécute et celui où sa mémoire réside sont deux questions distinctes, et les désynchroniser est l'un des moyens les plus simples de compromettre les performances. La prise en charge NUMA et le pinning CPU sont les deux leviers qui permettent de remédier à cela. Cet article explique le fonctionnement de la NUMA, comment la vérifier sous Linux et comment attribuer correctement les charges de travail pour les bases de données, l'entraînement en IA et les services sensibles à la latence.
Fonctionnement de NUMA sur les serveurs à plusieurs sockets
Un nœud NUMA (Non-Uniform Memory Access) est un groupe de cœurs de processeur liés à un bloc local de RAM via un contrôleur de mémoire dédié. Sur un serveur à deux sockets, on dispose généralement de deux nœuds. N'importe quel cœur peut lire n'importe quelle adresse, mais l'accès local prend environ 80 ns, tandis qu'un saut inter-sockets via l'UPI d'Intel ou l'Infinity Fabric d'AMD prend environ 130 à 150 ns. Sur des systèmes plus grands comportant davantage de sockets, le nœud le plus lent peut dépasser les 250 ns.
La bande passante suit le même schéma. Un système Sapphire Rapids à deux sockets peut atteindre environ 600 Go/s lorsque les cœurs accèdent à la mémoire locale, mais la liaison inter-sockets n'en représente qu'une fraction, ce qui fait que le trafic qui la traverse se retrouve rapidement gouloté. Les processeurs à nombreux cœurs rendent cela plus granulaire : le Sub-NUMA Clustering (SNC) d'Intel et le Nodes Per Socket (NPS) d'AMD divisent chaque socket en plusieurs domaines NUMA, de sorte qu'un boîtier « à deux sockets » peut facilement présenter quatre ou huit nœuds à Linux.
Sans prise en charge NUMA, le planificateur Linux migrera sans problème un thread d’un socket à l’autre tandis que son ensemble de travail restera sur le nœud d’origine. Chaque accès suivant devient alors un accès distant. Le symptôme visible est une utilisation élevée du CPU avec un débit réel faible, car les cœurs passent leur temps à attendre la mémoire. Les périphériques d’E/S aggravent ce problème. Un GPU ou une carte réseau est connecté à une racine PCIe spécifique, qui appartient à un nœud NUMA. Si le processus qui l'alimente s'exécute sur l'autre socket, chaque transfert DMA traverse l'interconnexion.
Inspection de la topologie NUMA sous Linux
Quatre outils couvrent presque tout ce dont vous avez besoin :
lscpupour un résumé rapide des sockets et des nœuds.numactl --hardwarepour les totaux de mémoire des nœuds et la matrice de distance entre les nœuds.numastatpour les compteurs de succès/échecs par processus.lstopo(à partir de hwloc) pour la hiérarchie du cache et la localisation des périphériques PCIe.
Commencez par numactl --hardware. Il répertorie chaque nœud, les cœurs et la mémoire qui lui appartiennent, ainsi que la matrice de distance. Une valeur de 10 correspond à une localisation locale, 20+ à une localisation distante. Si vous voyez un seul nœud sur un boîtier multi-sockets, cela signifie que l'entrelacement des nœuds est activé dans votre BIOS et que la topologie est masquée ; corrigez cela en premier (voir ci-dessous).
Pour un processus spécifique, numastat -p <PID> décompose l'emplacement réel de l'allocation de sa mémoire. Quatre compteurs sont importants :
numa_hit: mémoire allouée sur le nœud prévu. Vous souhaitez que cette valeur soit élevée.numa_miss: le nœud prévu était plein, l'allocation s'est étendue ailleurs.numa_foreign: un autre nœud a tenté d'allouer localement mais n'a pas pu, ce qui indique une pression sur la mémoire.other_node: pages allouées sur un nœud autre que celui où le processus s'exécute. Des valeurs élevées ici sont le signe classique d'un mauvais pinning.
Pour les charges de travail GPU ou NIC, exécutez lstopo-no-graphics et vérifiez à quel nœud NUMA chaque périphérique PCIe est connecté. Si les cœurs pilotant le périphérique se trouvent sur un autre nœud, c'est la première chose à corriger.
Fixation des cœurs de processeur et politiques de mémoire
Le pinning du CPU (ou affinité CPU) lie un processus à des cœurs spécifiques afin que le planificateur ne puisse pas le migrer. Cela ne suffit pas en soi, car Linux utilise par défaut une politique de mémoire « first-touch » : les pages sont allouées sur le nœud qui les écrit en premier. Si un thread démarre sur le mauvais nœud avant d'être épinglé, sa mémoire y reste. Il faut contrôler à la fois le placement et l'allocation.
Trois outils couvrent les cas courants :
| Outil | Commandes | Utilisation |
|---|---|---|
taskset | Cœurs de processeur uniquement | Liaison rapide et ponctuelle d'un processus existant |
numactl | Cœurs de processeur et mémoire | Lancement de charges de travail avec une localité stricte |
| systemd | Cœurs de processeur et mémoire, persistant | Services nécessitant un ancrage entre les redémarrages |
numactl prend en charge quatre politiques de mémoire :
--membind=N: allouer uniquement sur le nœud N, échouer si plein.--preferred=N: privilégier le nœud N, se rabattre sur les autres si nécessaire.--interleave=all: rotation entre les nœuds pour une répartition équilibrée de la bande passante.--localalloc: allouer sur le nœud où se trouve le processeur en cours d'exécution.
Fixer une charge de travail sur un nœud
Commencez par identifier les cœurs appartenant à votre nœud cible :
numactl --hardwareLancez ensuite l'application en la liant à ce nœud pour les cœurs et la mémoire :
numactl --cpunodebind=0 --membind=0 ./your_applicationPour un processus déjà en cours d'exécution, ajustez l'affinité CPU avec taskset:
taskset -cp 0-7 <PID>Pour que cela persiste après un redémarrage, configurez-le dans l'unité systemd :
[Service]
CPUAffinity=0-7
NUMAPolicy=bind
NUMAMask=0Rechargez et redémarrez :
sudo systemctl daemon-reload && sudo systemctl restart <service>Lorsque vous effectuez un pinning manuellement, désactivez l'auto-balancer du noyau afin qu'il n'interfère pas avec votre placement :
sysctl -w kernel.numa_balancing=0Ajoutez-le à /etc/sysctl.conf pour que cela soit permanent. Vérifiez ensuite avec numastat -p <PID> pendant quelques minutes de charge de travail réelle. Si other_node reste proche de zéro, l'ancrage est effectif.
Choisir une stratégie en fonction de la charge de travail
La politique appropriée dépend de la question de savoir si votre charge de travail tire davantage parti d'une faible latence ou d'une bande passante agrégée sur l'ensemble des nœuds.
| Charge de travail | Politique | Pourquoi |
|---|---|---|
| Bases de données (PostgreSQL, MySQL, SQL Server) | --cpunodebind + --membind | Grands tampons partagés, chemins de requête sensibles à la latence |
| Cache en mémoire (Redis, Memcached) | Liaison à nœud unique | Tout passe par la RAM, la latence à distance se manifeste immédiatement |
| Entraînement et inférence IA/ML | Liaison au nœud NUMA du GPU | Évite les transferts de tenseurs traversant les racines PCIe |
| Analyses (Spark, Elasticsearch) | --interleave=all | Un ensemble de travail volumineux nécessite de la bande passante sur tous les nœuds |
| API sensibles à la latence, trading | Affinité stricte entre broches et IRQ | La prévisibilité prime sur le débit de pointe |
| Forte utilisation du réseau (RoCEv2, InfiniBand) | Pin vers le nœud NUMA de la carte réseau, cœurs dédiés aux IRQ | Garde le traitement des interruptions au niveau local et à l'écart des threads d'application |
Pour les charges de travail GPU en particulier, exécutez lstopo pour déterminer sur quel nœud NUMA se trouve le GPU, puis lancez le processus d'entraînement ou d'inférence avec numactl --cpunodebind=N --membind=N pour ce même N. C'est l'une des améliorations les plus faciles à obtenir sur un serveur GPU à plusieurs sockets, car le placement par défaut du planificateur est souvent incorrect.
Pour les charges de travail HPC et MPI qui s'étendent sur les deux sockets, épinglez chaque rang à un seul nœud avec localalloc plutôt que d’entrelacer tout. Chaque rang dispose d’une mémoire locale, et le parallélisme s’effectue au niveau du rang.
Remarque pratique : si vous affectez un rang à un seul nœud, laissez-lui 2 à 4 Go de marge. Un nœud fonctionnant presque à pleine capacité déclenche une récupération de mémoire, ce qui vous fait perdre la latence que vous cherchiez à gagner.
Paramètres du BIOS et du noyau à vérifier
La précision des résultats fournis par l'outil dépend de la topologie exposée par le micrologiciel. Quelques paramètres à vérifier :
- Entrelacement des nœuds : désactivez-le. Lorsqu'il est activé, le BIOS présente toute la mémoire comme un seul pool plat et masque entièrement le NUMA au système d'exploitation.
numactl --hardwareaffiche un seul nœud sur un boîtier à plusieurs sockets si tel est le cas. - Clustering Sub-NUMA (Intel) ou Nodes Per Socket (AMD) : activez-le sur les processeurs à nombreux cœurs lorsque vous souhaitez une localisation plus fine. À vérifier
lscpuaprès le redémarrage. vm.zone_reclaim_mode: réglez sur 0 pour la plupart des serveurs de production. Une valeur non nulle récupère de manière agressive la mémoire locale plutôt que d'allouer à distance, ce qui peut évacuer le cache de pages utile.kernel.numa_balancing: laissez activé pour les charges de travail générales, désactivez lorsque vous effectuez un pinning manuel. L'équilibreur automatique migrera les pages et les threads d'une manière qui entre en conflit avec votre politique.
Si vous effectuez un réglage NUMA sur du matériel nu où vous contrôlez le BIOS, les paramètres du noyau et l'affinité IRQ, vous pouvez appliquer tout ce qui précède sans contourner les abstractions de l'hyperviseur. C'est la principale raison pour laquelle ce type de travail est plus facile sur du matériel dédié que sur des machines virtuelles dans le cloud.
Pour les serveurs dédiés multi-sockets avec accès root complet, consultez les serveurs dédiés de FDC.

Profils optimisés pour l'optimisation de la charge de travail des serveurs Linux
Comment choisir, appliquer et personnaliser les profils accordés pour les GPU, les bases de données et les serveurs Linux à large bande passante, avec des exemples et des conseils de déploiement Ansible.
16 min de lecture - 9 juin 2026
Linux OOM Killer Tuning for VPS : A Practical Guide (en anglais)
12 min de lecture - 8 juin 2026