Les sockets comme stratégie : pourquoi les plateformes comptent plus que les CPU aujourd’hui

Cet article vous a aidé ?

Quelqu’un vous appellera à 2 h 13 du matin parce que « le CPU n’est qu’à 35 % » alors que l’API rencontre des délais d’attente, la base de données est « aléatoirement lente » et les latences de stockage ressemblent à un sismographe. Vous fixerez des tableaux de bord qui jurent que tout va bien, tandis que les clients jurent le contraire.

C’est le piège moderne de la performance : nous achetons encore des serveurs comme s’il s’agissait d’un concours de beauté des CPU, mais la plupart des pannes et ralentissements en production sont des problèmes de plateforme : sockets, canaux mémoire, lignes PCIe, topologie NUMA et la façon dont l’I/O atteint réellement le silicium.

La vérité inconfortable : la plateforme est l’ordinateur

Nous aimons parler des CPU parce que leurs spécifications sont nettes : nombre de cœurs, GHz, tailles de cache. Les plateformes sont désordonnées : nombre de sockets, domaines NUMA, canaux mémoire, génération DDR et règles de population des DIMM, génération PCIe et routage des lignes, paramètres BIOS, firmware, IOMMU, routage des interruptions et un zoo sans cesse croissant d’accélérateurs.

En 2026, le CPU lui‑même est rarement le réactif limitant. Votre système bute sur les chemins entre le CPU et tout le reste :

  • Bande passante et latence mémoire (canaux, ranks, vitesse et si vos threads s’exécutent « près » de leur mémoire).
  • Topologie I/O (lignes PCIe, switches, bifurcation, où atterrissent les NVMe et les cartes réseau, et comment ils partagent les uplinks).
  • Tissu inter-socket (pénalités d’accès mémoire distant et trafic de cohérence de cache inter-socket).
  • Placement des interruptions et des files (paquets et complétions arrivant sur les mauvais cœurs).
  • Alimentation et thermique (comportement du boost, fréquences soutenues et différence entre la TDP marketing et la réalité).

Acheter « plus de CPU » peut ressembler à ajouter plus de caisses quand l’entrée du magasin n’est qu’une porte étroite. Vous pouvez embaucher autant de caissiers que vous voulez ; les clients ne peuvent toujours pas entrer.

Voici le changement de stratégie : les sockets ne sont plus de simples unités de calcul ; ce sont des décisions de topologie I/O et mémoire. Votre plateforme définit la forme de vos goulots d’étranglement avant même que votre logiciel n’exécute une instruction.

Une citation à garder sur un post‑it

Idée paraphrasée (John Ousterhout) : « Un système est rapide quand vous éliminez un grand goulot d’étranglement ; beaucoup de petites optimisations comptent peu. »

C’est tout le jeu. Trouvez le grand goulot. Et aujourd’hui, ce goulot est souvent la topologie de la plateforme, pas le débit d’instructions.

Faits et histoire intéressants qui expliquent le désordre

Quelques points de contexte qui font que le concept moderne de « sockets comme stratégie » ressemble moins à une conspiration et plus à de la physique et de l’économie :

  1. Le « Northbridge » était autrefois une puce séparée. Les contrôleurs mémoire et les complexes racines PCIe vivaient hors du CPU ; on pouvait gouloter un serveur entier sur un seul lien chipset partagé.
  2. Les contrôleurs mémoire intégrés ont tout changé. Une fois la mémoire intégrée au package CPU, les performances mémoire sont devenues fortement liées au choix du socket et aux règles de population des DIMM.
  3. NUMA existe depuis des décennies. Les serveurs multi-socket ont toujours eu un accès mémoire non uniforme, mais la pénalité est devenue plus visible à mesure que le nombre de cœurs augmentait et que les charges devenaient plus parallèles.
  4. PCIe a remplacé les bus partagés pour une raison. L’industrie a abandonné les bus parallèles partagés parce que la concurrence exigeait des liens point à point et des lignes évolutives.
  5. La virtualisation a transformé la topologie en politique logicielle. Les hyperviseurs peuvent cacher ou exposer NUMA, pinner des vCPU et placer la mémoire—parfois brillamment, parfois désastreusement.
  6. NVMe a rendu le stockage « adjacent au CPU ». L’I/O de stockage est passée des files HBA et du firmware vers des périphériques PCIe directs avec de profondes files, mettant la pression sur les interruptions, le cache et la bande passante mémoire.
  7. RDMA et le contournement du noyau ont fait de la carte réseau une partie de la plateforme. Quand la pile réseau migre en espace utilisateur ou que la NIC délègue, le placement des files et la localité PCIe deviennent des caractéristiques de performance.
  8. Les modèles de licence ont « armé » les sockets. Certains logiciels d’entreprise facturent par socket, par cœur ou par « unité de capacité », rendant les décisions de plateforme stratégiques financièrement, pas seulement techniquement.
  9. Les atténuations de sécurité ont modifié le profil de coût de certains travaux CPU. Pour certaines charges, les appels système et changements de contexte sont devenus plus coûteux, augmentant l’importance relative de minimiser l’overhead I/O et le bavardage inter-NUMA.

Ce ne sont pas des anecdotes. Elles expliquent pourquoi « acheter juste un CPU plus rapide » est de moins en moins le bon levier.

Ce qu’un « socket » vous apporte vraiment (et ce qu’il vous coûte)

Le nombre de sockets est une décision de topologie

Un socket est un package CPU physique, oui. Mais opérationnellement c’est aussi un ensemble de contrôleurs mémoire, de complexes racine PCIe et de points d’extrémité fabric. Ajouter un second socket peut ajouter plus de capacité et de bande passante mémoire, et plus de connectivité I/O—selon la plateforme. Cela ajoute aussi la possibilité d’accès mémoire distant et le surcoût de coordination inter-socket.

Dans un système mono-socket, le chemin heureux est simple :

  • Toute la mémoire est « locale ».
  • La plupart des périphériques PCIe sont à un saut.
  • Les erreurs de ordonnancement sont moins pénalisées.

Dans un système à deux sockets, vous devez gagner la performance :

  • Vos threads doivent s’exécuter sur le socket qui possède leurs allocations mémoire.
  • Votre NIC et vos NVMe doivent être sur le même socket que les cœurs les plus sollicités qui les traitent.
  • Votre charge doit soit bien évoluer à travers les nœuds NUMA, soit être épinglée et isolée.

Réalité brute : beaucoup de logiciels ne « scalent pas à travers les sockets ». Ils scalent avec les cœurs jusqu’à ce que le trafic inter-socket devienne la taxe que vous n’aviez pas budgétée.

Canaux mémoire : le régulateur silencieux de performance

Le nombre de cœurs vend des serveurs. Les canaux mémoire les font fonctionner.

Une plateforme avec plus de canaux mémoire par socket peut alimenter plus de cœurs avant qu’ils ne meurent de faim. Pour des charges intensives en mémoire (analytique, couches de cache, certaines bases de données, tas JVM sous pression, grands index en mémoire), la bande passante mémoire est souvent le plafond. Vous pouvez acheter un CPU avec plus de cœurs et voir le débit plafonner parce que les cœurs attendent la mémoire.

Mal peupler les DIMM et vous pouvez perdre de la bande passante. Beaucoup de plateformes exigent une population équilibrée entre les canaux. Mixer vitesses ou ranks peut rétrograder l’ensemble. Voilà pourquoi le choix de plateforme inclut des questions « ennuyeuses » comme : combien de canaux, quels types de DIMM et quelles règles de population.

Lignes PCIe : le budget I/O que vous ne pouvez pas dépasser

Chaque disque NVMe, NIC, GPU, DPU et HBA consomme des lignes PCIe et/ou partage des uplinks derrière des switches. Votre plateforme peut physiquement accueillir huit disques NVMe, mais électriquement ils peuvent partager moins d’uplinks que vous ne le pensez.

C’est une surprise courante en production : le serveur a assez de baies, mais pas assez de lignes. Alors vous découvrez ce que « x4 vers le backplane via un uplink switch » signifie vraiment en pointe.

Blague 1/2 : planifier les lignes PCIe, c’est comme organiser un placard—on l’ignore assez longtemps et on finit par se retrouver dans le noir en tenant des câbles qu’on n’a plus en mémoire.

NUMA : pas un bug, une taxe de réalité

NUMA n’est pas une fonctionnalité que vous activez. C’est ce qui arrive quand la mémoire est physiquement plus proche de certains cœurs que d’autres.

Les pénalités NUMA se manifestent par :

  • Des latences de queue élevées quand un thread chaud touche de la mémoire distante.
  • Un débit plus faible quand les caches et l’interconnexion saturent.
  • Des graphiques « mais le CPU n’est pas occupé » parce que les cœurs sont en attente, pas programmés.

Pour les piles de stockage et de réseau, NUMA interagit avec les interruptions, le DMA et le placement des files. Une NIC sur le socket 0 délivrant des interruptions à des cœurs sur le socket 1 est une régression de performance qu’on ne corrige pas par l’optimisme.

Les sockets comme stratégie d’entreprise (oui, vraiment)

En entreprise, les sockets sont aussi :

  • Des leviers de licence (les licences par socket incitent à moins de sockets plus gros ; par cœur poussent différemment).
  • Des leviers opérationnels (moins de sockets simplifie la planification de capacité et réduit la variance de performance « aléatoire » causée par NUMA).
  • Des leviers de risque (maturité de la plateforme, stabilité du firmware et chaîne d’approvisionnement pour les pièces de rechange).

Quand vous standardisez une plateforme, vous vous engagez à ses particularités : paramètres BIOS par défaut, exposition NUMA, mapping PCIe et cadence de mises à jour du firmware. Cet engagement dure plus longtemps que n’importe quelle génération de CPU.

Modes de défaillance : comment les plateformes créent une « lenteur mystérieuse »

1) Le mensonge « le CPU est inactif » : cœurs en attente et attentes cachées

L’utilisation CPU mesure le temps programmé, pas le progrès utile. Un cœur peut être « occupé » ou « inactif » tandis que votre charge attend la mémoire, l’I/O, des verrous ou l’accès NUMA distant. Les plateformes influencent ces attentes :

  • L’accès mémoire distant augmente la latence de chargement et le coût de cohérence.
  • Une bande passante mémoire insuffisante crée des stalls sur de nombreux cœurs simultanément.
  • La contention PCIe augmente la latence de complétion I/O et alourdit les queues de latence finale.

2) Les périphériques I/O qui se battent pour le même complexe racine

Si votre NIC et vos NVMe sont derrière le même uplink d’un switch PCIe, ils partagent la bande passante et peuvent entrer en contention sur les files de complétion. Cela devient visible quand les modèles de trafic s’alignent : gros bursts de réplication plus lectures NVMe lourdes ; fenêtres de sauvegarde plus pics d’ingestion ; un nœud Kubernetes faisant tout en même temps parce qu’« il a des cœurs ».

3) Tempêtes d’interruptions sur les mauvais cœurs

Le réseau et NVMe reposent sur des interruptions et/ou du polling. Si les interruptions tombent sur un petit ensemble de cœurs, ou pire, sur des cœurs éloignés du nœud NUMA du périphérique, vous obtenez :

  • Une forte activité softirq ou ksoftirqd.
  • Des pertes de paquets et des retransmissions sous charge.
  • Une latence accrue sans « saturation évidente du CPU ».

4) Échecs d’échelle dual-socket qui ressemblent à des bugs applicatifs

Certaines charges évoluent bien de 1 à N cœurs dans un socket, puis butent entre sockets. Symptômes :

  • Le débit plafonne à peu près au niveau d’un seul socket.
  • La latence tail empire en ajoutant des threads.
  • Les métriques de contention des verrous augmentent, mais les verrous ne sont pas la vraie cause—c’est le rebond de lignes de cache à distance.

5) Montées en capacité mémoire qui réduisent silencieusement la performance

Ajouter des DIMM peut forcer des vitesses plus basses ou des modes d’entrelacement différents. Ce n’est pas une théorie ; c’est une régression courante en production. Les upgrades mémoire doivent être traités comme des changements de performance, pas seulement de capacité.

6) « Même modèle de CPU » ne signifie pas même plateforme

Différents modèles de serveurs routent PCIe différemment, livrent des paramètres BIOS par défaut différents et exposent des comportements NUMA différents. Si vous supposez pouvoir déplacer une charge entre des serveurs « équivalents » et obtenir des performances identiques, vous apprendrez la topologie au pire moment possible.

Feuille de route de diagnostic rapide (premier/deuxième/troisième)

Voici la méthode que j’aimerais que plus d’équipes utilisent avant de deviner, redémarrer ou ouvrir un ticket « le CPU est lent ».

Premier : décidez si vous êtes lié au calcul, à la mémoire ou à l’I/O

  • Vérifiez la charge moyenne vs tâches exécutables, le vol de CPU et l’iowait.
  • Vérifiez les proxys de pression sur la bande passante mémoire (manques de cache, stalls) et le swap.
  • Vérifiez la latence de stockage et la profondeur des files ; vérifiez les pertes réseau et retransmissions.

Deuxième : cartographiez la topologie (NUMA + PCIe) et voyez si elle correspond au placement de votre charge

  • Identifiez les nœuds NUMA et les listes de CPU.
  • Cartographiez les NICs et les NVMe aux nœuds NUMA.
  • Vérifiez où les interruptions atterrissent et où vos processus s’exécutent.

Troisième : validez que la plateforme ne vous bride pas

  • Vérifiez le comportement des fréquences CPU sous charge.
  • Vérifiez les limites d’alimentation, l’étranglement thermique et les réglages firmware (C-states, P-states, limites turbo).
  • Confirmez que la mémoire fonctionne à la vitesse attendue et avec la configuration de canaux prévue.

Si vous suivez ces trois étapes, vous trouvez généralement le goulot d’étranglement en moins de 30 minutes. Si vous les sautez, vous pouvez passer trois jours à « optimiser » la mauvaise couche.

Tâches pratiques : commandes, sorties et décisions (12+)

Voici des tâches Linux exécutables que j’utilise pour diagnostiquer les goulots de plateforme. Chaque tâche inclut : commande, sortie représentative, ce que cela signifie et la décision qu’elle motive.

Tâche 1 : Identifier les sockets, nœuds NUMA et la topologie des cœurs

cr0x@server:~$ lscpu
Architecture:                         x86_64
CPU(s):                               64
Thread(s) per core:                   2
Core(s) per socket:                   16
Socket(s):                            2
NUMA node(s):                         2
NUMA node0 CPU(s):                    0-15,32-47
NUMA node1 CPU(s):                    16-31,48-63

Ce que cela signifie : Dual-socket, deux nœuds NUMA. Les CPU sont répartis ; les hyperthreads s’entrelacent.

Décision : Si sensibilité à la latence, envisagez d’épingler les charges dans un seul nœud NUMA ou d’assurer que les allocations mémoire suivent le placement CPU.

Tâche 2 : Vérifier la distribution mémoire par NUMA et si un nœud est à sec

cr0x@server:~$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 0 size: 257540 MB
node 0 free: 11844 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
node 1 size: 257676 MB
node 1 free: 182990 MB

Ce que cela signifie : Le nœud 0 est presque plein tandis que le nœud 1 est majoritairement libre. C’est un scénario classique d’allocations mémoire distantes et de latence tail.

Décision : Épinglez la charge au nœud 1, rééquilibrez les services ou imposez une politique mémoire (bind/membind/interleave) selon le comportement de la charge.

Tâche 3 : Vérifier si le noyau passe du temps à attendre l’I/O

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 892312  91340 8123432   0    0   120   340 4200 9800 18  4 76  2  0
 3  1      0 882104  91340 8126120   0    0  2140  1210 6100 12000 16  5 60 19  0
 2  1      0 879220  91340 8127001   0    0  1980  1400 5900 11700 15  5 62 18  0

Ce que cela signifie : « wa » (iowait) monte à ~19 %, et des processus bloqués (« b ») apparaissent. Probablement le chemin stockage ou une saturation.

Décision : Passez aux latences par périphérique (iostat), vérifiez les profondeurs de file et mappez la topologie NVMe/NIC.

Tâche 4 : Identifier la latence du stockage et la pression sur les files

cr0x@server:~$ iostat -x 1 3
Device            r/s   w/s   rkB/s   wkB/s  await  svctm  %util
nvme0n1         4200  1100  82000   34000   3.20   0.18  92.5
nvme1n1         4100  1200  80000   36000   3.40   0.19  94.1

Ce que cela signifie : Forte utilisation et await en hausse indiquent une approche de saturation. svctm faible suggère que le périphérique va bien ; c’est la mise en file qui pose problème.

Décision : Réduire la concurrence, répartir l’I/O sur plusieurs périphériques, vérifier si les deux périphériques partagent un uplink PCIe, ou déplacer la charge vers des disques/contrôleurs supplémentaires.

Tâche 5 : Valider les périphériques NVMe et leur largeur/vitesse de lien PCIe

cr0x@server:~$ sudo nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev
/dev/nvme0n1     S6X...               Samsung SSD 980 PRO 2TB                  1         2.00  TB /   2.00  TB      512   B +  0 B   5B2QGXA7
/dev/nvme1n1     S6Y...               Samsung SSD 980 PRO 2TB                  1         2.00  TB /   2.00  TB      512   B +  0 B   5B2QGXA7
cr0x@server:~$ sudo lspci -s 5e:00.0 -vv | egrep -i "LnkCap|LnkSta"
LnkCap: Port #0, Speed 16GT/s, Width x4
LnkSta: Speed 8GT/s, Width x4

Ce que cela signifie : Le périphérique supporte PCIe Gen4 (16GT/s) mais fonctionne en Gen3 (8GT/s). C’est un problème de plateforme/firmware/emplacement, pas un « NVMe lent ».

Décision : Vérifier les paramètres BIOS PCIe, la compatibilité des risers, le câblage des slots et si un switch/backplane force Gen3.

Tâche 6 : Cartographier les périphériques PCIe aux nœuds NUMA

cr0x@server:~$ for d in /sys/bus/pci/devices/*; do \
  dev=$(basename "$d"); \
  numa=$(cat "$d/numa_node" 2>/dev/null); \
  class=$(cat "$d/class" 2>/dev/null); \
  if [ "$numa" != "-1" ]; then echo "$dev numa=$numa class=$class"; fi; \
done | head
0000:3b:00.0 numa=0 class=0x010802
0000:3c:00.0 numa=0 class=0x020000
0000:af:00.0 numa=1 class=0x010802
0000:b0:00.0 numa=1 class=0x020000

Ce que cela signifie : Vous avez des NVMe et des NIC attachés aux deux nœuds NUMA. Bien—si vous placez les charges en conséquence.

Décision : Placez les services intensifs en stockage près de leurs NVMe et les services intensifs en réseau près de leurs NIC, ou gardez un hôte « single-NUMA » pour les applications sensibles à la latence.

Tâche 7 : Vérifier où votre processus s’exécute (affinité CPU)

cr0x@server:~$ ps -o pid,psr,comm -p 21488
  PID PSR COMMAND
21488  52 postgres

Ce que cela signifie : Le processus tourne actuellement sur le CPU 52, qui (d’après lscpu) est dans le nœud NUMA 1.

Décision : Vérifiez ses allocations mémoire et ses périphériques I/O sur le nœud 1. Si non, épinglez-le ou déplacez les périphériques/IRQs.

Tâche 8 : Vérifier le placement mémoire NUMA du processus

cr0x@server:~$ sudo numastat -p 21488
Per-node process memory usage (in MBs) for PID 21488 (postgres)
Node 0          18240.50
Node 1           2201.75
Total           20442.25

Ce que cela signifie : Le processus s’exécute sur le nœud 1 mais la majeure partie de la mémoire vit sur le nœud 0. C’est de l’accès mémoire distant et une taxe de latence.

Décision : Redémarrez avec une politique NUMA correcte (bind CPU + mémoire), ajustez le placement du service ou utilisez l’entrelacement pour les charges de débit.

Tâche 9 : Inspecter la distribution des interruptions et les points chauds

cr0x@server:~$ cat /proc/interrupts | egrep "nvme|mlx|eth" | head
  142:  1982341   10234      0      0  IR-PCI-MSI 524288-edge  nvme0q0
  143:  2059933   10111      0      0  IR-PCI-MSI 524289-edge  nvme0q1
  192:   982341  110993  809221  774112 IR-PCI-MSI 1048576-edge  mlx5_comp0
  193:   100112  989231  802331  790002 IR-PCI-MSI 1048577-edge  mlx5_comp1

Ce que cela signifie : Les files NVMe frappent principalement les groupes CPU0/CPU1 (premières colonnes). Les complétions NIC sont plus réparties.

Décision : Ajustez l’affinité IRQ pour les files NVMe/NIC afin d’étaler la charge et l’aligner sur le NUMA. Si les IRQ s’accumulent sur quelques CPU, vous obtiendrez une contention softirq et des pics de latence.

Tâche 10 : Confirmer le comportement de fréquence CPU et l’étranglement

cr0x@server:~$ sudo turbostat --Summary --quiet --show Busy%,Bzy_MHz,TSC_MHz,PkgTmp,PkgWatt -i 2 -n 2
Busy%   Bzy_MHz  TSC_MHz  PkgTmp  PkgWatt
42.31   2498     2500     86      205.4
44.02   2299     2500     89      205.0

Ce que cela signifie : La fréquence occupée baisse tandis que la température du package augmente. Vous pouvez être limité par l’alimentation/thermique, ce qui ressemble à un « CPU ralenti ».

Décision : Vérifiez les limites d’alimentation, le refroidissement, le profil d’alimentation BIOS et les limites de boost soutenu. N’« optimisez » pas le code tant que la plateforme n’est pas stable.

Tâche 11 : Détecter pertes réseau et retransmissions (la plateforme peut en être la cause)

cr0x@server:~$ ip -s link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    RX:  bytes  packets  errors  dropped  missed  mcast
    9812331123  9923123  0       18422    0       223
    TX:  bytes  packets  errors  dropped  carrier collsns
    8123341123  8123311  0       0        0       0

Ce que cela signifie : Des pertes en RX. Cela peut venir d’un débordement de ring buffer/queue, de problèmes d’IRQ/placement CPU, ou de contention PCIe—pas seulement « le réseau ».

Décision : Vérifiez RSS/compte de queues, affinité IRQ, statistiques du driver NIC et si la NIC partage la bande passante PCIe avec des NVMe lourds.

Tâche 12 : Confirmer la distribution des queues et RSS de la NIC

cr0x@server:~$ ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:             32
TX:             32
Other:          0
Combined:       0
Current hardware settings:
RX:             8
TX:             8
Other:          0
Combined:       0

Ce que cela signifie : La NIC peut faire 32 queues mais vous en utilisez 8. Si vous avez beaucoup de cœurs et du trafic intense, 8 peut devenir un goulot.

Décision : Augmentez les queues (avec prudence), puis alignez les IRQ sur des CPU locaux NUMA. Plus de queues sans affinité peut se retourner contre vous.

Tâche 13 : Inspecter les réglages de la couche bloc (NVMe)

cr0x@server:~$ cat /sys/block/nvme0n1/queue/nr_requests
128

Ce que cela signifie : La profondeur de la file bloc peut limiter le parallélisme pour une charge de débit—ou être volontairement basse pour la latence.

Décision : Pour le débit batch, pensez à augmenter. Pour les charges sensibles à la latence, restez conservateur et corrigez d’abord la topologie.

Tâche 14 : Déterminer si vous swappez ou si le noyau récupère agressivement

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           503Gi       412Gi        11Gi       1.2Gi        80Gi        63Gi
Swap:           16Gi       2.0Gi        14Gi

Ce que cela signifie : Un peu d’utilisation de swap. Pas toujours fatal, mais pour de la latence critique c’est un drapeau rouge ; cela interagit aussi avec le déséquilibre NUMA.

Décision : Identifiez le service qui consomme la mémoire, corrigez les fuites, limitez les caches ou déplacez la charge. Le swap est souvent un problème de dimensionnement de plateforme, pas de simple tuning.

Tâche 15 : Vérifier les indices de trafic inter‑NUMA via les domaines du planificateur

cr0x@server:~$ cat /proc/sys/kernel/numa_balancing
1

Ce que cela signifie : Le rééquilibrage NUMA automatique est activé. Il peut aider les charges générales, mais nuire aux charges à latence prévisible en migrant des pages.

Décision : Pour les systèmes sensibles à la latence avec pinning explicite, envisagez de le désactiver et de gérer le placement délibérément. Pour les charges mixtes ou les serveurs généralistes, laissez‑le activé et mesurez.

Trois mini-récits d’entreprise depuis le terrain

Mini-récit 1 : L’incident causé par une mauvaise hypothèse

Une équipe a migré une couche d’API à fort trafic d’une ancienne plateforme dual-socket vers une plateforme dual-socket « plus récente et plus rapide ». Même fournisseur de CPU, fréquences supérieures, plus de cœurs. Cela semblait une victoire nette. Les tests de charge passaient. La fenêtre de changement était calme. Puis est arrivé le lundi.

La latence tail a grimpé. Pas la latence moyenne—seulement le 99e centile. Le graphe de dépendances de l’API s’est illuminé : timeouts vers Redis, ralentissements sporadiques de la base, et pertes de paquets intermittentes au niveau du load balancer. L’utilisation CPU n’a jamais dépassé 50 %, ce qui a rendu tout le monde suspicieux de la couche applicative. On a commencé à blâmer un « déploiement récent », qui n’avait rien à voir.

L’hypothèse erronée était subtile : « Dual-socket est dual-socket. » Sur les nouveaux serveurs, la NIC et le périphérique NVMe de boot atterrissaient sur le socket 0, mais les pods les plus chargés du runtime de conteneur étaient programmés sur les deux sockets. Les interruptions étaient majoritairement traitées par des CPU du socket 0, tandis que la moitié du traitement réseau se faisait sur le socket 1. Les paquets traversaient les sockets, les allocations mémoire rebondissaient, et une petite contention est devenue une usine à latence tail.

Une fois qu’ils ont épinglé les pods lourds en réseau au nœud NUMA de la NIC, aligné l’affinité IRQ et arrêté de laisser l’ordonnanceur étaler les threads chauds sur les sockets, le problème a disparu. Le matériel n’était pas plus lent. La plateforme était différente, et le système payait une taxe topologique à chaque requête.

Leçon : ne considérez jamais « mêmes sockets et cœurs » comme « même performance ». Traitez le mapping de la plateforme comme une condition préalable au déploiement, comme les règles de pare-feu ou les certificats TLS.

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Une équipe stockage voulait plus de débit sur des nœuds NVMe servant une charge de recherche intense. Quelqu’un a remarqué que l’utilisation CPU était modérée et a conclu que le système était « sous-exploité ». Le plan : augmenter la concurrence. Augmenter les profondeurs de file I/O, augmenter le nombre de workers applicatifs et ajuster les queues NIC « pour correspondre au nombre de cœurs ».

Ça a marché pour le benchmark. Ça marche toujours. En charge synthétique stable, le débit a augmenté.

Puis le trafic production est arrivé : des rafales, des motifs mixte lecture/écriture, des manques de cache et des compactions d’arrière-plan périodiques. Les latences tail ont doublé. La plateforme a atteint un régime où interruptions et complétions se disputaient le cache et la bande passante mémoire. Les profondeurs de files augmentées ont amplifié la mise en file, transformant de micro-bursts en arrêts visibles par l’utilisateur.

La partie sournoise était l’observabilité. La latence moyenne ne paraissait pas horrible. Le CPU n’était toujours pas saturé. Mais le chemin de complétion était devenu chaotique : plus de queues signifiaient plus d’interruptions, plus de rebonds de lignes de cache et plus de bavardage inter-NUMA parce que les workers supplémentaires n’étaient pas épinglés. L’« optimisation » avait augmenté la contention plus qu’elle n’avait augmenté le travail utile.

La correction n’a pas été de tout annuler. Ils ont conservé une augmentation modeste du parallélisme, puis ont fait la partie ennuyeuse : aligner les queues sur des cœurs NUMA locaux, limiter les profondeurs de file pour préserver la latence et séparer la compaction sur un ensemble de CPU dédié. Le débit est resté bon. La latence tail a cessé d’effrayer l’astreinte.

Leçon : plus de parallélisme n’est pas égal à plus de performance. Sur les plateformes modernes, le parallélisme peut devenir une attaque par déni de service contre votre propre hiérarchie mémoire.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Un groupe d’infra a standardisé une plateforme serveur pour sa flotte de bases de données. Pas seulement le modèle CPU : SKU plateforme, paramètres BIOS, versions firmware, schéma de population DIMM, usage des slots PCIe et un mapping documenté des NIC/NVMe aux nœuds NUMA. C’était si ennuyeux que ça en semblait cérémonial.

Six mois plus tard, un fournisseur a livré un lot de cartes mères de remplacement pendant une pénurie. Les cartes de remplacement étaient « équivalentes » mais avaient des paramètres BIOS par défaut différents et un routage PCIe légèrement différent. Quelques hôtes ont commencé à montrer des lags de réplication intermittents et des pics de latence d’écriture occasionnels.

Parce que l’équipe avait une base de référence plateforme, ils l’ont détecté rapidement. Ils ont comparé les hôtes problématiques au référentiel connu‑bon : placement des périphériques par nœud NUMA, vitesse du lien PCIe, distribution des IRQ et profil d’alimentation BIOS. Les différences sautaient aux yeux. Ils ont corrigé les paramètres BIOS, déplacé une NIC dans le slot prévu et réappliqué leur politique d’affinité IRQ. Problème résolu avant que ce soit un rapport d’incident.

La pratique qui les a sauvés n’était pas magique. C’était traiter la configuration de plateforme comme du code : une baseline, un diff et un état sain que vous pouvez restaurer. La plupart des équipes ne font pas cela car ce n’est pas glamour. La plupart des équipes passent aussi plus de temps à lutter contre des incendies.

Leçon : La standardisation semble lente jusqu’au moment où vous en avez besoin. Ensuite, elle est plus rapide que les exploits héroïques.

Erreurs courantes : symptômes → cause racine → correction

1) Symptom : CPU < 50 %, mais la latence est terrible

Cause racine : Stalls mémoire, accès NUMA distant ou mise en file I/O. L’utilisation CPU n’affiche pas les cycles en attente.

Correction : Vérifiez le placement mémoire NUMA (numastat), la latence stockage (iostat -x) et la distribution des IRQ. Épinglez les services chauds sur un nœud NUMA et alignez les périphériques.

2) Symptom : Les performances ont empiré après avoir ajouté de la RAM

Cause racine : La population DIMM a forcé une vitesse mémoire inférieure ou des canaux déséquilibrés ; la latence/bande passante mémoire a changé.

Correction : Vérifiez la vitesse mémoire dans le BIOS/firmware, assurez une population équilibrée, évitez de mélanger les types de DIMM. Traitez les montées en mémoire comme des changements de performance et retestez.

3) Symptom : Débit NVMe inférieur à l’attendu sur des disques « Gen4 »

Cause racine : Le lien s’est entraîné en Gen3 ou x2 ; mauvais slot, riser ou limitation du backplane.

Correction : Confirmez avec lspci -vv le statut du lien ; ajustez les paramètres BIOS PCIe ; déplacez le périphérique vers un slot attaché au CPU.

4) Symptom : Pertes réseau pendant les périodes intensives en stockage

Cause racine : La NIC et les NVMe partagent un uplink/root complex PCIe ; le trafic de complétion entre en contention ; les IRQ tombent sur des cœurs surchargés.

Correction : Cartographiez la topologie PCIe, déplacez un périphérique vers l’autre socket/root complex si possible ; ajustez l’affinité IRQ ; augmentez les queues seulement après un placement correct.

5) Symptom : Un serveur dual-socket plus lent qu’un mono-socket pour le même service

Cause racine : Mémoire et rebonds de lignes de cache inter-socket ; l’ordonnanceur étale les threads ; les allocations distantes dominent.

Correction : Contraintez le service à un socket ; allouez la mémoire localement ; séparez les voisins bruyants ; reconsidérez si vous aviez réellement besoin du dual-socket.

6) Symptom : Effets de « voisin bruyant » dans les microservices malgré suffisamment de cœurs

Cause racine : Ressources plateforme partagées : contention du LLC, saturation de la bande passante mémoire, uplinks PCIe partagés, pression IRQ.

Correction : Utilisez des CPU sets et un placement NUMA-aware ; réservez les charges à forte bande passante mémoire ; séparez les pods I/O-intensifs sur des hôtes avec un layout PCIe propre.

7) Symptom : Les benchmarks sont excellents ; la latence tail en production est mauvaise

Cause racine : Les benchmarks sont à état stable ; la production est éclatée. Queueing + interruptions + GC/compaction amplifient les rafales.

Correction : Testez avec des patterns en rafales, limitez les profondeurs de file, isolez le travail d’arrière-plan et préférez un placement prévisible plutôt que la concurrence maximale.

Blague 2/2 : Si votre plan est « ajoutez des threads jusqu’à ce que ce soit rapide », félicitations—vous avez réinventé le thundering herd, maintenant avec du PCIe.

Listes de contrôle / plan étape par étape

Checklist de sélection de plateforme (avant d’acheter ou de standardiser)

  1. Définissez le goulot d’étranglement attendu : bande passante mémoire, pps réseau, latence stockage, débit GPU, ou mixte.
  2. Choisissez le nombre de sockets intentionnellement : mono-socket pour une latence prévisible ; dual-socket quand vous avez vraiment besoin de plus de mémoire/I/O et que votre logiciel est NUMA-aware.
  3. Validez les besoins de canaux mémoire : bande passante requise, règles de population DIMM et vitesse attendue en pleine population.
  4. Comptez les lignes PCIe comme de l’argent : NICs, NVMe, GPUs/DPUs, HBAs ; supposez que vous utiliserez chaque ligne achetée.
  5. Demandez la carte des slots PCIe : quels slots se connectent à quel CPU/root complex ; où vont les uplinks du backplane.
  6. Planifiez les interruptions et les queues : suffisamment de cœurs près de la NIC/NVMe ; évitez de forcer tout l’I/O sur un seul socket.
  7. Considérez l’impact des licences : par-socket/par-cœur modifie le choix « optimal » de sockets.
  8. Standardisez BIOS et firmware : profil d’alimentation, C-states, génération PCIe, SR-IOV et exposition NUMA.

Checklist de déploiement (avant qu’une charge n’arrive)

  1. Enregistrez les sorties lscpu et numactl --hardware comme baseline hôte.
  2. Mappez les NIC/NVMe aux nœuds NUMA via /sys/bus/pci/devices/*/numa_node.
  3. Confirmez les largeurs et vitesses de liens PCIe pour les périphériques critiques.
  4. Définissez la politique d’affinité IRQ (ou confirmez que les valeurs par défaut de la distro correspondent à votre intention).
  5. Décidez du placement : un nœud NUMA par service (latence) vs interleave (débit).
  6. Chargez les tests avec trafic en rafales et tâches d’arrière-plan activées (compaction, sauvegardes).

Checklist d’incident (quoi faire sous pression)

  1. Vérifiez si le goulot est I/O, mémoire ou étranglement de fréquence CPU avant de toucher à la config applicative.
  2. Confirmez si la latence tail corrèle avec un déséquilibre NUMA, des pertes ou de la mise en file stockage.
  3. Si multi-socket : contraignez la charge à un socket comme mitigation (pas comme solution finale).
  4. Réduisez la concurrence si la mise en file est le problème ; n’« augmentez pas les threads » dans une tempête.
  5. Capturez des snapshots avant/après de la topologie et de la distribution des IRQ pour éviter des corrections placebo.

FAQ

1) Les serveurs mono-socket sont-ils généralement meilleurs maintenant ?

Pour beaucoup de services sensibles à la latence, oui : NUMA plus simple, moins de surprises inter-socket et souvent suffisamment de cœurs. Le dual-socket est excellent quand vous avez réellement besoin de plus de capacité mémoire, de bande passante ou de lignes I/O, et que votre charge est correctement placée.

2) Si l’utilisation CPU est faible, pourquoi mon service est lent ?

Parce que l’utilisation ne mesure pas les cycles en attente. Vous pouvez être bloqué sur le stockage, attendre la mémoire ou faire rebondir des lignes de cache entre sockets. Diagnostiquez la mise en file et le placement avant de blâmer l’application.

3) Quelle est la façon la plus rapide de détecter un problème NUMA ?

Comparez le placement CPU vs le placement mémoire du processus. Si le processus tourne sur le nœud 1 mais que la majeure partie de sa mémoire est sur le nœud 0, vous avez probablement trouvé votre latence tail. Utilisez ps et numastat -p.

4) Dois‑je désactiver le rééquilibrage NUMA automatique ?

Parfois. Si vous épinglez explicitement CPU et mémoire pour une latence prévisible, le rééquilibrage NUMA peut jouer contre vous en migrant des pages. Pour des charges mixtes ou des serveurs généralistes, il peut aider. Mesurez ; n’appliquez pas aveuglément.

5) Plus de queues NIC améliore toujours la performance, non ?

Non. Plus de queues peut augmenter les interruptions et le churn de cache, et peut répartir le travail à travers les sockets si vous ne gérez pas l’affinité. Augmentez les queues seulement après avoir confirmé que l’affinité IRQ et le placement CPU sont sensés.

6) Comment savoir si mon NVMe est limité électriquement par la plateforme ?

Vérifiez la largeur et la vitesse du lien PCIe avec lspci -vv. Si LnkCap montre Gen4 x4 mais que LnkSta montre Gen3 ou un lien plus étroit, vous perdez de la performance à cause de contraintes de slot/backplane/BIOS.

7) Pourquoi les benchmarks sont bons mais la production est mauvaise ?

Les benchmarks sont contrôlés. La production comporte des rafales, des charges mixtes, des tâches d’arrière-plan, du GC et des voisins bruyants. Ceux‑ci amplifient la mise en file et les erreurs de topologie. Testez toujours en condition de rafales et avec le travail d’arrière-plan réel activé.

8) Le dual-socket est‑il toujours pire pour les bases de données ?

Non. Les bases de données peuvent bien évoluer sur dual-socket quand elles sont configurées avec conscience NUMA, placement mémoire adéquat et I/O local. Le mode d’échec est « tout laisser par défaut », où threads, mémoire et interruptions circulent librement.

9) Comment les sockets se rapportent-ils spécifiquement au design stockage ?

Les chemins de stockage utilisent DMA et files de complétion. Si vos NVMe sont sur un socket et que vos threads de stockage tournent sur l’autre, vous paierez des hops mémoire distants et fabric sur chaque I/O. Alignez la pile : périphérique, IRQs et threads sur le même nœud NUMA.

10) Quelle est une habitude plateforme qui réduit les incidents ?

Basez votre topologie et votre firmware comme vous basez la configuration OS. Quand quelque chose « change mystérieusement », vous pouvez comparer la réalité à l’état connu‑bon au lieu de déboguer des légendes urbaines.

Prochaines étapes réalisables cette semaine

Si vous voulez moins de mystères de performance et moins de débats à 2 h du matin sur des graphiques CPU, faites ces actions dans l’ordre :

  1. Inventoriez la topologie sur votre flotte : sockets, nœuds NUMA et localité des périphériques. Stockez‑la avec l’enregistrement hôte.
  2. Choisissez une politique de placement par défaut : single‑NUMA pour les couches latence ; interleave pour les couches débit. Faites‑le intentionnellement, pas par accident.
  3. Standardisez les paramètres BIOS/firmware pour les profils d’alimentation et la génération PCIe. « Les paramètres d’usine » ne sont pas une stratégie de fiabilité.
  4. Créez un runbook d’incident utilisant la feuille de route de diagnostic rapide ci‑dessus. Mettez les commandes dedans. Rendez‑le exécutable sous pression.
  5. Réalisez une expérience contrôlée : épinglez un service critique à un socket et mesurez la latence tail. Si elle s’améliore, vous avez appris quelque chose d’actionnable sur votre plateforme.

Le titre n’est pas « Les CPU ne comptent pas ». Ils comptent. Mais le mouvement gagnant aujourd’hui est de traiter le socket—et la plateforme qui l’entoure—comme l’unité de stratégie. Achetez la topologie avec intention. Exploitez‑la comme si vous en aviez vraiment besoin.

← Précédent
Ubuntu 24.04 : Quand les offloads GRO/LRO/TSO cassent tout — Comment tester et désactiver en toute sécurité
Suivant →
MySQL vs SQLite : le cas de la « vitesse gratuite » — quand une base fichier bat un serveur

Laisser un commentaire