...

Politiques de mémoire NUMA pour les grands serveurs de bases de données : optimisation ciblée des performances

Mémoire NUMA Pour les grands serveurs de bases de données, cela détermine à quelle distance les threads opèrent par rapport à la mémoire requise et dans quelle mesure les latences influencent les temps de réponse et le débit. J'adapte de manière ciblée l'affectation des cœurs de processeur, le placement en mémoire et la taille de la charge de travail, je réduis les accès distants et j'obtiens ainsi une solution fiable et prévisible Performance.

Points centraux

  • Topologie Comprendre : prendre en compte de manière ciblée les nœuds, les cœurs, la mémoire vive (RAM) et les interconnexions.
  • Politiques Choisir l'option appropriée : « Strict », « Preferred » ou « Interleave » en fonction de l'objectif de la charge de travail.
  • affinité Mise en œuvre : liaison locale des threads, des IRQ et de la mémoire.
  • VMs au niveau du nœud : affecter les vCPU et la mémoire RAM à un nœud NUMA.
  • Suivi Effectuer : mesurer les lectures à distance, la latence P99 et la charge des nœuds.

Comprendre la topologie NUMA

Je commence chaque optimisation par la Topologie: Combien y a-t-il de nœuds NUMA, comment les cœurs sont-ils répartis, comment la mémoire vive est-elle connectée aux sockets, et quel est le coût des accès inter-nœuds ? L'accès à la mémoire locale prend nettement moins de temps qu'un accès au-delà des limites d'un nœud, c'est pourquoi j'évite les À distance-méthodes. Les grands serveurs de bases de données tirent profit d'une planification des charges de travail qui permet de maintenir les threads et les données sur le même nœud. Si le volume de données actives ne tient pas dans un seul nœud, je planifie délibérément la répartition plutôt que de m'en remettre au comportement par défaut. C'est ainsi que je maintiens la Latence faible et permet un débit régulier, même en cas de charge élevée.

Choisir correctement les paramètres du BIOS et de la configuration matérielle

Je vérifie dans le BIOS que Entrelacement de nœuds est désactivée afin de préserver la séparation NUMA. Je répartis les canaux de mémoire de manière symétrique par socket et je veille à la configuration (1DPC vs 2DPC) afin d'éviter toute baisse inutile de la fréquence d'horloge et de la bande passante. Des fonctionnalités telles que États C Et pour les modes d'économie d'énergie agressifs, je règle les objectifs de latence de manière plus prudente, afin que les cœurs n'aient pas à se réveiller sans cesse. SMT/hyper-threading J'évalue cela en fonction de la charge de travail : pour les charges de travail OLTP fortement dépendantes de la mémoire, je limite le nombre de threads SMT actifs en parallèle par cœur afin de réduire la pression sur le cache et la variabilité. Je vérifie également que les périphériques PCIe (cartes réseau, NVMe) sont connectés localement par socket, afin que leur IRQs et que les chemins DMA ne traversent pas l'interconnexion. En mettant en place une configuration rigoureuse à ce niveau, on jette les bases sur lesquelles les politiques et les affinités peuvent produire leurs effets.

Bien choisir les politiques de mémoire

Le choix de la Politique détermine à partir de quel nœud le noyau alloue de la mémoire et comment fonctionnent les solutions de repli. Le paramètre « Strict » fixe des limites strictes et interrompt les allocations si le nœud cible ne dispose pas d'espace suffisant ; cela donne la priorité à Performance En matière de flexibilité. Le mode « Preferred » privilégie un nœud, mais se rabat sur d'autres en cas de pénurie, offrant ainsi un juste milieu. Le mode « Interleave » répartit les pages selon le principe du « round-robin » entre plusieurs nœuds, ce qui peut s’avérer judicieux pour des volumes de données très importants et utilisés de manière uniforme. Pour de nombreuses bases de données, une stratégie locale utilisant « Preferred » ou « Strict » est généralement la meilleure solution. Choix.

Politique Conduite Utilisation typique Avantages Risques
Strict Utilise uniquement la mémoire du nœud cible, sinon une erreur se produit Critique latente Bases de données avec une planification claire des nœuds Au maximum local Accès, latences prévisibles L'allocation peut échouer si le nœud est plein
Préféré Nœud préféré, possibilité de basculer vers d'autres Généralités Charges de travail avec une charge variable Une bonne proximité et une flexibilité acceptable Augmentation du télétravail en période de pénurie
Interleave Round-robin sur plusieurs nœuds Très vaste, largement utilisé Données Répartition de la charge entre plusieurs nœuds Localisation moins favorable, latence potentiellement plus élevée

Threads, affinité CPU et liaison mémoire

Je mappe les threads aux cœurs du nœud cible, je lie la mémoire avec numactl et j'aligne les IRQ de manière à ce que Données rester local. Cette combinaison entre l'affinité CPU et le « memory binding » réduit les lectures à distance coûteuses et resserre la distribution des temps d'exécution. Pour un contrôle granulaire, j'utilise des politiques au niveau des processus ou des threads et je maintiens le pool de tampons aussi près que possible des threads de travail actifs. Si vous souhaitez approfondir le sujet, vous trouverez des étapes pratiques pour Affinité avec le CPU, qui peuvent être appliquées directement sur des hôtes de production. C'est ainsi que je garantis la cohérence Latence même lorsque le système est fortement sollicité.

Donner la priorité aux Hotsets locaux

J'identifie les hotsets de la Charge de travail et je les place strictement localement, tandis que les données froides peuvent être stockées de manière plus flexible. Grâce à cette hiérarchisation, je reste proche de la mémoire vive du nœud pour les chemins principaux. Lorsque la charge augmente, la solution s'adapte parfaitement, car les chemins coûteux continuent de s'exécuter localement. Sans cet ordre, la courbe de latence se dégrade dès que les threads accèdent de plus en plus souvent à des données situées sur d'autres nœuds. Une Reliure empêche de manière fiable ce comportement précis.

Fusionner le NUMA de stockage et le NUMA réseau

Je classe NICs et NVMe-J'affecte de manière ciblée les périphériques aux sockets et redirige leurs IRQ vers les cœurs locaux. Je maintiens la cohérence du Receive/Transmit Steering (RSS/RPS/XPS) par nœud, afin que les paquets soient traités là où s'exécutent les threads de la base de données. Avec NVMe, j’utilise plusieurs files d’attente par cœur et j’ancrage les threads d’E/S localement, afin que les chemins de journalisation et de données ne transitent pas par l’interconnexion. Pour la réplication, je sépare les chemins réseau par nœud, afin que les flux WAL/Redo entrants aboutissent localement. Ainsi, IO– et les chemins d'accès au processeur sont congruents, et la base de données ne gaspille pas de cycles en effectuant des copies inutiles à travers le réseau de mémoire.

Planifier les machines virtuelles en fonction de la taille des nœuds

Je dimensionne les machines virtuelles de manière à ce que le nombre de vCPU et la mémoire vive tiennent dans un nœud NUMA physique, car cela permet de réduire Latence et le trafic d'interconnexion. Les machines virtuelles „ Wide VMs », dont la taille dépasse celle d'un nœud, répartissent inévitablement les accès à la mémoire et perdent ainsi en prévisibilité. Lorsqu'une machine virtuelle doit être plus grande, je planifie explicitement le vNUMA et veille à une répartition symétrique entre les nœuds. Du côté de l’hôte, j’évite la sursouscription pour les charges de travail sensibles à la latence et je réserve de la mémoire locale à chaque VM. « » fournit un aperçu rapide de la structure physique des nœuds.„Planification des nœuds NUMA“, ce qui facilite la prise de décision concernant la taille de la VM et Erreur lors de la mise en place.

Tenir compte des paramètres de l'hyperviseur

Je vérifie la manière dont l'hyperviseur présente le vNUMA et je conserve l'affectation des groupes de vCPU aux Noyaux de manière cohérente. De plus, je veille à ce que la topologie NUMA de la machine virtuelle corresponde à celle de l'hôte, afin que le planificateur puisse rester local. Je limite autant que possible les réservations de mémoire et les règles d'anti-affinité, tout en les appliquant aussi strictement que nécessaire. Je préfère remplacer une forte densité de machines virtuelles sur un seul socket par une répartition proche des nœuds. C'est ainsi que je gère À distance- Réduis au minimum les accès et assure la stabilité des chemins d'E/S.

Pratique des conteneurs et de l'orchestration

Dans les conteneurs, je mets cpuset- Limites cohérentes : processeurs et masques de mémoire associés (cpuset.cpus, cpuset.mems) vont de pair. Les « systemd-slices » et les « units » se voient attribuer des affinités CPU fixes afin que le noyau applique bien la préférence de mémoire. Au niveau des couches d'orchestration, je prévois des pods/services près du nœud, j'utilise des évaluations topologiques et une allocation statique des cœurs de processeur afin d'éviter qu'une charge de travail ne bascule d'un nœud à l'autre. Je déclare explicitement les Huge Pages par pod/conteneur et je maintiens leur taille et leur nombre stables par nœud. Important : j’affecte les processus d’infrastructure et les processus secondaires (journalisation, sidecars, sauvegardes) à d’autres cœurs, voire à l’autre nœud NUMA, afin de ne pas perturber les hotsets de la base de données.

Équilibrage NUMA et optimisation du système d'exploitation

L'équilibrage NUMA automatique peut optimiser les ressources locales Accès améliorer lorsque les charges de travail migrent ou que les phases changent radicalement. Je l'utilise de manière ciblée, mais je vérifie si le déplacement des pages dans un sens puis dans l'autre n'est pas plus gênant qu'utile. Les processus bien définis présentant une affinité claire tirent souvent davantage profit de politiques définies manuellement que d’un rééquilibrage constant. Je vérifie les paramètres du noyau, la gestion des IRQ et les Huge Pages transparentes au cas par cas, en fonction de la base de données et de la plateforme. Ce document me sert de point de départ : NUMA-Balancing-Guide permettant de tester les paramètres étape par étape et de dispersion de réduire les latences.

Utiliser les « Huge Pages » de manière ciblée

J'utilise les « Huge Pages » pour réduire les échecs de TLB et les grandes Mémoirepour traiter plus efficacement ces zones. Pour les serveurs de bases de données, je réserve les pages à l'avance, je les attribue à des nœuds et je vérifie si l'instance les utilise réellement. Je désactive souvent les « Transparent Huge Pages » lorsque des objectifs de latence sont fixés et je configure des « Huge Pages » statiques afin que l'allocation reste déterministe. La proximité avec le nœud NUMA reste toutefois déterminante ; les Huge Pages renforcent une bonne stratégie, mais ne la remplacent pas. Ceux qui ignorent cela n'y gagnent pratiquement rien. Performance et s'expose à des effets secondaires lors de la pagination.

Dimensionnement des bases de données : pool de mémoire tampon et charge de travail

Je planifie le volume de travail actif de manière à ce que le pool de tampons, les caches de verrouillage et de planification, ainsi que les éléments les plus sollicités tableaux tenir dans un nœud. Pour les instances de très grande taille, je répartis les services ou les shards entre les nœuds, plutôt que de déployer une énorme instance monolithique sur l'ensemble des nœuds. Pour les cas OLTP, je maintiens le pool de tampons par nœud à un niveau compact et je donne la priorité aux taux de réussite locaux. Pour les analyses OLAP, l’interleave peut s’avérer utile dans des cas particuliers, lorsque le volume de données est gigantesque et homogène. Sans cette discipline, le Interconnexion-Le trafic et épuise les réserves précisément au moment où surviennent les pics de charge.

Astuces spécifiques aux bases de données

Je tiens compte du modèle de processus et de threads du moteur : PostgreSQL Comme cela utilise des processus, je configure l'instance principale, Autovacuum et Checkpointer séparément pour chaque nœud et je conserve shared_buffers localement par shard. Pour MySQL/InnoDB je classe instances du pool de mémoire tampon sur les nœuds et aligne localement les threads d'E/S et les modules d'écriture dans les journaux. Serveur SQL bénéficie d'un Soft-NUMA adapté et d'une allocation qui répartit les planificateurs et les groupes de mémoire entre les nœuds physiques. Oracle- Je configure les instances avec des « Large Pages » locales et je répartis les serveurs de traitement et d'E/S entre les nœuds. De manière générale, je réduis les conflits d'arène de l'allocateur (par exemple jemalloc) grâce à des arènes adaptées à la structure NUMA et je veille à ce que Gestionnaire de verrouillage et que les points chauds de verrouillage restent localisés, en effectuant un partitionnement et un sharding au niveau des nœuds.

Suivi : les indicateurs qui comptent

Je mesure les lectures à distance, le trafic d'interconnexion entre nœuds, les erreurs de page par nœud et le P99-Latence des requêtes concernées. Je surveille également l'utilisation du processeur par nœud, les taux de NUMA Miss et la proportion d'accès à la mémoire locale. Cette vue permet de déterminer si la politique est efficace ou si des threads accèdent de manière incontrôlée à des pages distantes. Je mets en corrélation les pics avec les décisions du planificateur, les événements de migration et les erreurs d’allocation. Seules ces métriques confirment que la Politique non seulement en laboratoire, mais aussi de manière permanente dans le système de production.

Stratégie de test et déploiement

Je procède à des tests par étapes : je commence par des micro-benchmarks pour Bande passante et la latence par nœud, puis des charges de travail réalistes avec des caches « froids » et « chauds ». J'augmente progressivement les niveaux de charge, je mesure les valeurs P95/P99/P99,9 et j'observe la répartition, pas seulement les moyennes. Je documente chaque modification (stratégie, affinités, Huge Pages, redirection des IRQ) et je réalise des tests A/B dans des conditions identiques. Avant le déploiement, je définis Critères d'interruption et un plan de repli pour pouvoir revenir rapidement à la configuration précédente en cas de régression. Un bref test de stabilisation sous charge continue permet de vérifier Dérive et des migrations qui restent invisibles à court terme.

Procédure étape par étape

Je commence par saisir les Topologie: nombre de nœuds, affectation des cœurs, canaux de mémoire et interconnexion. Je détermine ensuite la charge de travail cible par nœud et vérifie si les « hotsets » s’y intègrent. À l’étape suivante, je configure l’affinité CPU, le routage des IRQ et le « memory binding » au niveau des processus ou des threads. Ensuite, j’active ou désactive l’équilibrage NUMA en fonction de la dynamique de la charge de travail et, si nécessaire, je réserve des Huge Pages par nœud. Enfin, je vérifie le résultat à l’aide de tests de charge reproductibles et je surveille Chiffres clés en fonctionnement continu.

Exemples concrets et obstacles

Une instance OLTP comportant de nombreuses transactions courtes gagne sensiblement en performance lorsque je configure les threads de travail et le pool de tampons sur un Nœuds et de définir „ Strict “ ou « Preferred ». Un entrepôt de données avec des scans larges peut tirer parti de l'interleave si les données sont utilisées de manière très homogène et si les nœuds sont bien sollicités. Les machines virtuelles perdent sensiblement en prévisibilité dès qu’elles dépassent les limites des nœuds et que l’hyperviseur alloue la mémoire de manière décalée. Je constate souvent qu’une seule machine virtuelle « étendue » surcharge l’interconnexion et ralentit ainsi les machines virtuelles voisines. Ces effets disparaissent dès que je passe à une configuration locale Affectation et que je revienne à une configuration vNUMA propre.

Scénarios d'erreur et anti-modèles

Avec Strict j'augmente le risque que les allocations échouent et que le mécanisme OOM-Killer intervienne. C'est pourquoi je garde des marges disponibles sur le nœud cible, je surveille les échecs et je définis des solutions de repli (par exemple, un redimensionnement ciblé en dehors des heures de pointe). Les pages transparentes géantes dans le alwaysMode - provoquant des chemins de latence Défragmentation et les écuries – j'utilise des réservations statiques ou j'active THP madvise. L'équilibrage NUMA automatique peut déplacer les pages d'un côté à l'autre en cas de charge oscillante ; si je détecte des phénomènes de « page bounce », je réapplique les règles manuellement. Dans les machines virtuelles, Ballooning et la compression de la mémoire, un véritable fléau pour la prévisibilité ; je désactive ces fonctions pour les bases de données critiques. Je ne planifie les migrations en direct entre nœuds que pendant les fenêtres d'indisponibilité, ou je transfère d'abord les données côté base de données afin d'éviter que l'interconnexion ne soit saturée de manière secondaire.

Planification des capacités et croissance

Je prévois, par nœud, une Réserve Je configure 10 à 20 % pour les pics de charge, l'Autovacuum/Compaction et les tâches de maintenance périodiques. Si le volume de données augmente, je commence par faire évoluer la capacité au niveau des nœuds (shards/services), plutôt que d'agrandir aveuglément l'ensemble du pool de tampons. J’empêche toute „ croissance insidieuse “ en fixant des limites strictes par nœud et en mettant en place des alertes dès que les taux de réussite locaux baissent ou que les parts à distance augmentent. Dans mes projections pour les prochains trimestres, je tiens compte non seulement du volume de données, mais aussi Taux de transaction et des répartitions d'accès modifiées, car celles-ci déplacent souvent les hotsets plus rapidement que les besoins en mémoire proprement dits. La plateforme reste ainsi stable, et les extensions s'effectuent de manière contrôlée, sans sacrifier la localité NUMA.

Bilan succinct

J'optimise les grands serveurs de bases de données en NUMA- Je combine de manière optimale la topologie, les politiques et la taille des charges de travail. L'allocation locale de mémoire permet de gagner ces millisecondes décisives, tandis que les accès à distance imprévus font grimper la latence P99. À l'avenir, je prévois de planifier les machines virtuelles de manière à ce qu'elles s'intègrent dans les nœuds ou exploitent clairement le vNUMA. J’utilise de manière ciblée les paramètres du système d’exploitation, les affinités et les Huge Pages, j’en vérifie l’impact et je ne déploie les modifications qu’après avoir effectué des mesures. Ceux qui suivent ces étapes obtiennent les performances attendues Performance composé de matériel informatique moderne et garantit la rapidité et la fiabilité des plateformes, même en cas de charge élevée.

Derniers articles