Je montre comment Serveur d'équilibrage NUMA sur le matériel d'hébergement, rationalise l'accès à la mémoire et réduit les latences en liant les processus et les données au nœud NUMA approprié. Le facteur décisif est la Optimisation de l'accès à la mémoire grâce à l'accès local, au placement de tâches et à la migration ciblée de pages sur des hôtes Linux dotés de nombreux cœurs.
Points centraux
- NUMA sépare les CPU et la mémoire en nœuds ; les accès locaux fournissent faible Latence.
- Automatique NUMA Balancing migre les pages et place les tâches près du nœud.
- Taille de VM par nœud, sinon il y a risque de NUMA-Trashing.
- Outils comme le montrent numactl, lscpu, numad Topologie et l'utilisation.
- TuningC-States, Node Interleaving off, Pages géantes, Affinités.
Ce qu'est NUMA - et pourquoi cela compte pour l'hébergement
NUMA divise un système multiprocesseur en Nœuds, qui contiennent chacun leur propre CPU et mémoire locale, ce qui rend les accès proches plus rapides que les accès distants. Alors qu'UMA envoie tous les cœurs sur un chemin commun, NUMA évite les goulets d'étranglement grâce à local canaux de mémoire par nœud. Dans les environnements d'hébergement avec de nombreuses machines virtuelles parallèles, chaque milliseconde de latence s'additionne, c'est pourquoi chaque demande est mesurable. Pour ceux qui souhaitent approfondir le sujet, vous trouverez plus d'informations sur l'utilisation de l'espace de stockage en ligne. Architecture NUMA. Pour moi, une chose est sûre : celui qui comprend et utilise les nœuds tire davantage de bande passante du même matériel.
L'équilibrage automatique NUMA dans le noyau Linux - comment il fonctionne
Le noyau scanne périodiquement des parties de l'espace d'adressage et „démappe“ des pages pour qu'un hinting fault ne bloque pas l'accès à l'espace d'adressage. optimal nœuds est visible. Si le défaut se produit, l'algorithme évalue s'il vaut la peine de migrer la page ou de déplacer la tâche et évite les mouvements inutiles. Migrate-on-Fault apporte Données plus près de l'unité centrale exécutante, le placement de tâches NUMA rapproche les processus de leur mémoire. Le scanner répartit son travail au coup par coup afin que l'overhead reste dans le bruit de la charge normale. Il en résulte un réglage fin permanent qui réduit la latence sans exiger de règles d'épinglage strictes.
Optimisation de l'accès à la mémoire : le local bat le distant
Les accès locaux utilisent le Contrôleur de mémoire du propre nœud et minimisent les temps d'attente pour l'interconnexion. Les accès à distance coûtent des cycles via QPI/UPI ou Infinity Fabric et réduisent ainsi le temps de connexion effectif. Bande passante. Un nombre élevé de cœurs accentue cet effet, car de plus en plus de cœurs sont en concurrence pour les mêmes connexions. Je planifie donc de manière à ce que le code chaud et les données actives se retrouvent sur un nœud. Si l'on ne respecte pas cette règle, on perd des points de pourcentage qui sont décisifs pour le temps de réponse ou le timeout lors des pics de charge.
Tailles de VM, NUMA-Trashing et découpage de l'hôte
Je dimensionne les VM de manière à ce que les vCPU et la RAM tiennent dans un nœud NUMA, afin d'éviter les accès inter-nœuds. Souvent, 4 à 8 vCPU par nœud fournissent de bonnes Taux de réussite, Cela dépend de la plateforme et de la hiérarchie du cache. De plus, les Huge Pages aident, car le TLB travaille plus efficacement et les migrations de pages sont moins fréquentes. Si nécessaire, je mets en place Affinité du CPU pour les processus critiques en termes de latence, afin de lier les threads aux noyaux appropriés - pour plus d'informations, voir Affinité du CPU. Celui qui étire des VM sur des nœuds risque le NUMA trashing, c'est-à-dire un ping-pong de données et de threads.
Outils en pratique : numactl, lscpu, numad
Avec „lscpu“, je lis Topologie et les nœuds NUMA, y compris l'affectation des noyaux. „numactl -hardware“ m'indique la mémoire par nœud et les distances disponibles, ce qui facilite l'évaluation des chemins. Le démon „numad“ observe l'utilisation et adapte les affinités de manière dynamique lorsque les centres de charge se déplacent. Pour les scénarios fixes, j'utilise „numactl -cpunodebind/-membind“ pour épingler explicitement les processus et la mémoire. Je combine ainsi l'équilibrage automatique avec des directives ciblées et je contrôle le résultat via „perf“, „numastat“ et „/proc“.
Comment je mesure l'impact : Indicateurs et commandes
J'évalue toujours NUMA-Tuning sur Séries de mesures, et non par intuition. Trois indicateurs ont fait leurs preuves : Rapport entre le nombre de pages consultées localement et le nombre de pages consultées à distance, taux de migration et répartition de la latence (P95/P99).
- À l'échelle du système: „numastat“ montre les accès locaux/distants et les pages migrées par nœud.
- En fonction du processus: „/proc//numa_maps“ révèle où se trouve la mémoire et comment elle a été répartie.
- Vue de l'ordonnanceur: „Cpus_allowed_list“ et véritable „Cpus_allowed“ vérifient si les liens sont effectifs.
# Vue à l'échelle du système
numastat
numastat -m
# Distribution et binds liés au processus
pid=$(pidof )
numastat -p "$pid"
cat /proc/"$pid"/numa_maps | head
cat /proc/"$pid"/status | grep -E 'Cpus_allowed_list|Mems_allowed_list
taskset -cp '$pid"
# Compteur du noyau pour l'activité NUMA
grep -E "numa|migrate' /proc/vmstat
# Événements de trace pour l'analyse en profondeur (activer brièvement)
echo 1 > /sys/kernel/debug/tracing/events/mm/enable
sleep 5 ; cat /sys/kernel/debug/tracing/trace | grep -i numa ; echo 0 > /sys/kernel/debug/tracing/events/mm/enable
Je compare à chaque fois A/B: non lié vs. lié, équilibrage automatique on/off et différents découpages de VM. L'objectif est une nette diminution des accès distants et du bruit de migration ainsi que des latences P95/P99 plus faibles. Ce n'est que lorsque les valeurs mesurées sont stables et meilleures que je me charge du réglage.
Paramètres du BIOS et du firmware qui portent vraiment
Je désactive „Node Interleaving“ dans le BIOS pour que la structure NUMA reste visible et que le noyau local peut planifier. Des C-States réduits stabilisent les pics de latence, car les noyaux tombent moins souvent en état de sommeil profond, ce qui permet d'économiser du temps de réveil. J'attribue les canaux de mémoire de manière symétrique afin que chaque nœud puisse utiliser sa capacité maximale. Bande passante est atteint. Je teste les fonctions Prefetcher et RAS avec des profils de charge de travail, car elles aident ou nuisent selon le modèle d'accès. Je mesure chaque modification par rapport à une ligne de base et ce n'est qu'ensuite que j'adopte le réglage de manière permanente.
Paramètres du noyau et de Sysctl qui font la différence
Le réglage fin dans le noyau m'aide, Overhead et Temps de réaction de l'équilibreur en fonction de la charge de travail. Je commence avec des valeurs par défaut conservatrices et j'avance progressivement.
- kernel.numa_balancingOn/Off de l'équilibrage automatique. Pour les charges itinérantes, il reste activé chez moi ; pour les services spéciaux strictement épinglés, je le désactive à titre d'essai.
- kernel.numa_balancing_scan_delay_ms: temps d'attente avant le premier balayage après la création du processus. Choisir plus grand si beaucoup de tâches à courte durée de vie sont en cours d'exécution ; plus petit pour les services à longue durée de vie qui ont besoin d'une proximité rapide.
- kernel.numa_balancing_scan_period_min_ms / _max_ms: largeur de bande des intervalles de balayage. Des intervalles serrés augmentent la réactivité, mais aussi la charge de l'unité centrale.
- kernel.numa_balancing_scan_size_mb: proportion de l'espace d'adressage par balayage. Trop grand, il génère des tempêtes d'erreurs, trop petit, il réagit paresseusement.
- vm.zone_reclaim_modeEn cas de manque de mémoire, le noyau préfère la récupération locale à l'allocation à distance. Pour les charges de travail d'hébergement générales, je laisse généralement 0; pour les services strictement sensibles à la latence et localisés en mémoire, je teste prudemment des valeurs plus élevées.
- Transparent Huge Pages (THP): Sous „/sys/kernel/mm/transparent_hugepage/{enabled,defrag}“, je règle généralement sur madvise et une défragmentation conservatrice. Les profils durs „always“ apportent certes des avantages en termes de TLB, mais risquent de provoquer des décrochages en raison de la compaction.
- sched_migration_cost_ns: estimation des coûts pour la migration des tâches. Des valeurs plus élevées atténuent la redistribution des ordonnanceurs agressifs.
- cgroups cpuset: Avec cpuset.cpus et cpuset.mems je sépare proprement les services par nœud et je m'assure que Première touche reste dans les limites des nœuds autorisés.
# Exemple : équilibrage conservateur mais réactif
sysctl -w kernel.numa_balancing=1
sysctl -w kernel.numa_balancing_scan_delay_ms=30000
sysctl -w kernel.numa_balancing_scan_period_min_ms=60000
sysctl -w kernel.numa_balancing_scan_period_max_ms=300000
sysctl -w kernel.numa_balancing_scan_size_mb=256
# Utiliser THP avec précaution
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
echo defer > /sys/kernel/mm/transparent_hugepage/defrag
Il reste important de le faire : Ne modifier qu'une seule vis de réglage par cycle de test et tester l'effet contre la même courbe de charge. C'est ainsi que je démêle la cause et l'effet.
Placer correctement les charges de travail : Bases de données, caches, conteneurs
Les bases de données bénéficient du fait que les buffer pools par nœud NUMA restent locaux et que les threads sont liés à proximité de leurs tas. Dans les caches en mémoire, je règle le sharding sur Nœuds afin d'éviter les fetchs distants. Les plateformes de conteneurs reçoivent des limites et des requêtes de manière à ce que les pods ne sautent pas à travers les nœuds. Pour les réservations de mémoire, j'utilise Huge Pages, ce qui permet de mieux placer les hotsets dans les Caches s'adapter à la situation. Le tableau suivant résume de manière compacte les stratégies et les effets typiques.
| Stratégie | Utilisation | Effet attendu | Remarque |
|---|---|---|---|
| Première touche | Bases de données, JVM-Heaps | Allocation latérale locale | Exécuter l'initialisation sur le nœud cible |
| Interleave | Charge largement répartie | Répartition uniforme | Pas optimal pour les hotspots |
| Épinglage des tâches | Services critiques en termes de latence | Latence constante | Moins de flexibilité lors des changements de charge |
| Équilibrage automatique | Charges de travail mixtes | Proximité dynamique | Évaluer les frais généraux par rapport aux bénéfices |
| Pages géantes | Grands tas, caches | Moins de mésaventures TLB | Prévoir une réservation propre |
Virtualisation : NUMA virtuel, planificateur et personnalisation des invités
Virtual NUMA transmet la topologie de l'hôte à l'OS invité sous une forme simplifiée, de sorte que First-Touch et Allocateur travailler de manière judicieuse. Les planificateurs d'hyperviseur font attention à la proximité des nœuds lorsqu'ils déploient des vCPU et migrent des VM. J'aligne rarement les grosses VM sur plusieurs nœuds, sauf si la charge de travail diffuse largement et profite de l'entrelacement. Dans l'invité, j'adapte les tas de JVM ou de bases de données de manière à ce qu'ils restent locaux sur des nœuds NUMA visibles. Pour la gestion de la mémoire dans l'invité, un coup d'œil sur mémoire virtuelle, pour dompter la taille des pages et le swapping.
Proximité de la PCIe : NVMe et NIC aux bons nœuds
Si possible, j'attribue les SSD NVMe et les cartes réseau rapides au nœud sur lequel les Charge de travail est en cours d'exécution. J'évite ainsi que les demandes d'E/S ne traversent l'interconnexion et n'ajoutent de la latence. Je lie les NIC multi-queues aux ensembles de noyaux d'un nœud à l'aide de RSS/RPS, afin que les IRQ restent locales. Pour les piles de stockage, il est intéressant de diviser les pools de threads par nœud. En faisant attention à cela, on réduit sensiblement les temps de latence P99 et on crée une marge de manœuvre pour les pics de charge.
L'affinité IRQ et Queue dans la pratique
Je vérifie d'abord sur quel Nœud NUMA et épingler les IRQ et les queues de manière appropriée. De cette manière, la localité du chemin de données est préservée.
# Affectation d'un appareil à un nœud
cat /sys/class/net/eth0/device/numa_node
cat /sys/block/nvme0n1/device/numa_node
# Définir l'affinité IRQ de manière ciblée (exemple : noyaux 0-7 d'un nœud)
irq=
echo 0-7 > /proc/irq/$irq/smp_affinity_list
# Lier les queues de NIC aux noyaux (RPS/RFS)
for q in /sys/class/net/eth0/queues/rx-* ; do echo 0-7 > "$q"/rps_cpus ; done
sysctl -w net.core.rps_sock_flow_entries=32768
for q in /sys/class/net/eth0/queues/rx-* ; do echo 4096 > "$q"/rps_flow_cnt ; done
# Améliorer l'affinité de la file d'attente NVMe
echo 2 > /sys/block/nvme0n1/queue/rq_affinity
cat /sys/block/nvme0n1/queue/scheduler # "none" préféré
„irqbalance“, je l'exécute avec la conscience du noeud ou je mets exceptions pour les interruptions hot-path. Il en résulte des latences plus stables, moins de sauts d'IRQ entre les nœuds et une augmentation mesurable des occurrences d'E/S locales.
Liaison statique vs. équilibrage dynamique - la voie médiane
Avec „taskset“ et cgroups, je fixe des règles strictes lorsque des Latence compte. Je laisse l'Automatic NUMA Balancing actif lorsque la charge se déplace et que j'ai besoin d'une proximité adaptative. Un mélange fonctionne souvent mieux : des pins durs pour les hotpaths, des limites plus ouvertes pour le travail secondaire. Je vérifie régulièrement si les migrations augmentent de manière significative, car cela signale une mauvaise planification. L'objectif reste de choisir des emplacements de données et de threads de telle sorte que les migrations restent rares, mais possibles.
NUMA dans les conteneurs et Kubernetes
J'apporte le conteneur cpusets et Pages géantes sur la ligne. J'attribue des pods/conteneurs à un nœud NUMA en déposant des quantités cohérentes de CPU et de mémoire. Dans les orchestrations, je place des politiques qui privilégient les affectations à un seul nœud et respectent ainsi le premier contact.
- Runtime du conteneur: „-cpuset-cpus“ et „-cpuset-mems“ maintiennent les tâches et la mémoire ensemble ; allouer les Huge Pages comme ressources.
- Gestionnaire de topologie/de CPUAllocations : Les allocations strictes ou préférentielles garantissent l'attribution de noyaux et de zones de mémoire associés.
- QoS garantieRequêtes/limites fixes minimisent les redistributions par l'ordonnanceur.
Je divise délibérément les sidecars et les processus auxiliaires sur d'autres noyaux au sein de du même nœud, afin que le hotpath ne soit pas perturbé, mais ne se retrouve pas dans la course aux nœuds croisés.
Comprendre les topologies de CPU : CCD/CCX, SNC et Cluster-on-Die
Les processeurs pour serveurs actuels décomposent les sockets en Sous-domaines avec leurs propres caches et chemins. J'en tiens compte lorsque je découpe des noyaux/seaps :
- AMD EPYCCCD/CCX et „NUMA per Socket“ (NPS=1/2/4) influencent la finesse du découpage NUMA. Plus de nœuds (NPS=4) augmentent la localité, mais exigent un épinglage propre.
- IntelSub-NUMA Clustering (SNC2/4) divise le LLC en clusters. Bon pour les charges liées à la mémoire, à condition que l'OS et la charge de travail soient conscients des nœuds.
- Proximité de L3Je lie les threads qui utilisent les mêmes tas dans la même interconnexion L3 afin d'économiser le trafic de cohérence et les sauts de clusters croisés.
Ces options agissent comme un multiplicateur : bien utilisées, elles soulèvent Localité en plus - mal configurés, ils augmentent la fragmentation et le trafic à distance.
Introduction progressive et plan de retour en arrière
Je n'introduis jamais le NUMA-Tuning „Big Bang“. Un résilient Plan évite les surprises :
- Ligne de base: topologie matérielle, latences P50/P95/P99, throughput, capture du quota numastat.
- Hypothèse: Formuler un objectif concret (par exemple, accès à distance -30%, P99 -20%).
- Une étape: ne modifier qu'une seule vis de réglage (par ex. découpe VM, cpuset, politique THP, intervalles de balayage).
- CanaryTester sur 5-10% de la flotte sous charge réelle, avoir le rollback prêt.
- Évaluation: comparer les valeurs mesurées, définir des fenêtres de régression, consigner les effets secondaires.
- DéploiementDéroulement : arbre par arbre, mesurer à nouveau après chaque arbre.
- Entretien: Remesurer tous les trimestres (les mises à jour du noyau, du firmware, de la charge de travail modifient l'optimum).
Je m'assure ainsi que les améliorations sont reproductibles et qu'elles peuvent être annulées en quelques minutes en cas d'erreur.
Erreurs fréquentes - et comment les éviter
Un faux pas typique est l'activation de l'entrelacement des nœuds dans le BIOS, ce qui cache la topologie NUMA et Équilibrage de la machine. Tout aussi défavorables : les VM avec plus de vCPU qu'un nœud n'en offre, ainsi que les Huge Pages réservées de manière peu soignée. Certains administrateurs épinglent tout en dur et se privent ainsi de toute flexibilité lorsque les charges de travail se déplacent. D'autres s'en remettent entièrement au noyau, bien que les zones sensibles dures exigent des règles claires. J'enregistre les séries de mesures, j'identifie rapidement les valeurs aberrantes et j'adapte progressivement la configuration et les politiques.
- THP „toujours“ sans contrôle : une compression non planifiée perturbe la latence. Je préfère utiliser „madvise“ et réserver les Huge Pages de manière ciblée.
- vm.zone_reclaim_mode trop agressif : la récupération locale peut faire plus de mal que de bien au mauvais moment. Mesurer d'abord, affûter ensuite.
- irqbalance aveugleLes IRQ non critiques se déplacent à travers les nœuds. Pour les hotpaths, je mets des exceptions ou des masques fixes.
- Mélange interleave + épinglage durDes politiques opposées génèrent un ping-pong. J'opte pour une ligne claire par service.
- Des cpusets pas très propresLes conteneurs voient certes un nœud, mais mappent la mémoire dans d'autres nœuds. Toujours définir „cpuset.mems“ de manière cohérente par rapport à l'ensemble de l'unité centrale.
- Fonctionnalités Sub-NUMA activés, mais non utilisés : Plus de nœuds sans planification augmentent la fragmentation. N'activer qu'après des tests.
En bref
NUMA Balancing Server rapproche de manière ciblée les processus et les données, ce qui permet d'augmenter la fréquence et la qualité des accès locaux. Latence être plus courte. Avec une taille de VM adaptée, une configuration propre du BIOS et des outils comme numactl, on obtient une topologie claire que le noyau exploite. Virtual NUMA, Huge Pages et affinités complètent l'équilibrage automatique au lieu de le remplacer. En connectant les appareils I/O à proximité des nœuds et en plaçant des hotpaths, on élimine les accès à distance coûteux. Ainsi, le matériel d'hébergement s'adapte de manière fiable et chaque seconde de CPU fournit plus d'énergie. charge utile.


