Receive Side Scaling à 10 et 25 Gbit/s : optimisation des performances pour les réseaux de serveurs Linux modernes

Mise à l'échelle côté réception répartit de manière ciblée le trafic réseau sur plusieurs cœurs via des liaisons à 10 et 25 Gbit/s, afin que les serveurs Linux puissent traiter des débits élevés avec une faible latence. Je vais vous montrer concrètement comment j'active RSS, qui Queues de billard sur le dossier « Cores » et éviter ainsi les goulots d'étranglement au niveau des interruptions et des coups de cache.

Points centraux

Je vais résumer brièvement les points essentiels pour que tu puisses rapidement planifier les prochaines étapes.

  • Répartition de la charge: Les paquets sont répartis sur plusieurs cœurs via plusieurs files d'attente.
  • localité du cache: Un flux reste toujours sur la même file d'attente.
  • Hachage: Le hachage par quadruplets répartit les flux de manière uniforme entre les files d'attente.
  • affinité: Un mappage ciblé des IRQ réduit les latences.
  • Mise à l'échelle: À partir de 10/25 Gbit/s, la technologie RSS garantit un débit élevé.

Ces points sont étroitement liés et constituent la base de la Performance sur des charges de travail réelles. Je donne la priorité d'abord au nombre correct de files d'attente, puis à la CPU-Affinité. Je vérifie ensuite les paramètres de hachage et les réglages fins.

Ce qu'apporte le « Receive Side Scaling »

RSS divise la réception des paquets en plusieurs Files d'attente de réception, que j'affecte à des cœurs de processeur spécifiques afin qu'aucun cœur ne devienne un goulot d'étranglement. Cela permet de réduire les pics d'interruptions matérielles et de lisser le traitement via des SoftIRQ, ce qui réduit les pics de latence et augmente le débit. Chaque file d’attente déclenche ses propres interruptions, que j’associe de manière fixe à des cœurs afin de garantir la cohérence des chemins de données. Cette cohérence favorise la Cache-Localisation, car un flux rencontre toujours le même noyau. C'est précisément cette interaction qui se traduit directement par une efficacité mesurable lorsque les cadences PPS sont élevées.

Voici comment fonctionne le RSS sur le plan technique

La carte réseau (NIC) génère, à partir des adresses IP source et destination ainsi que des ports source et destination, un Hash et l'utilise comme index pour la table d'indirection, qui pointe vers des files d'attente. De cette manière, les paquets d'un flux aboutissent toujours dans la même file d'attente et restent ainsi liés au même noyau. Les différents flux se répartissent de manière homogène, à condition que les clés de hachage et les champs de protocole soient configurés de manière appropriée. Le travail se rapproche ainsi de la Matériel informatique, ce qui réduit la charge de travail du noyau et diminue la surcharge. C'est exactement ce que je souhaite afin de maintenir un faible taux de traitement des paquets par cœur à 10G/25G.

Pourquoi le RSS est-il important à partir de 10 et 25 Gbit/s ?

À 1 Gbit/s, c'est souvent un seul Noyau la charge des paquets, mais à partir de 10 Gbit/s, l'équilibre bascule rapidement. Les petits paquets font grimper le nombre de PPS, ce qui fait qu'un cœur atteint rapidement 100 % de charge et que des pertes apparaissent. C'est précisément à ce moment-là que le RSS agit comme un multiplicateur de bande passante utilisable. Je répartis la charge sur plusieurs Cores, réduit les changements de contexte et stabilise davantage les courbes de latence. Résultat : ce n'est qu'avec un RSS propre que le débit réel se rapproche du débit de la liaison.

Configurer le flux RSS sur le serveur Linux

Sous Linux, je gère principalement les flux RSS via ethtool, les options du pilote et le sysfs, afin que les capacités de la carte réseau soient pleinement exploitées. Je commence par lire le nombre maximal de canaux de réception, puis je définis un nombre de files d'attente adapté au processeur. Ensuite, je vérifie le hachage RSS pour TCP/UDP et, en option, pour les VLAN ou le tunneling, afin que la répartition des profils de charge reste correcte. Pour le bruit de fond de la répartition des interruptions, je m’aide de Équilibrage de l'IRQ, même si je préfère marquer manuellement les files d'attente critiques. C'est ainsi que je les associe Queues de billard s'adapte étroitement à la topologie de l'hôte et empêche les déplacements indésirables.

Table d'indirection, clé RSS et réglage fin du hachage : commandes concrètes

Je commence par vérifier la répartition actuelle et la clé de la carte réseau :

ethtool -x eth0 # : afficher la table d'indirection (files d'attente de réception) et la clé RSS
ethtool -n eth0 rx-flow-hash tcp4
ethtool -n eth0 rx-flow-hash udp4

Pour obtenir une répartition propre et uniforme, je règle la table d'indirection sur le nombre de files d'attente souhaité. Avec 16 files d'attente, j'opte pour un mappage uniforme :

ethtool -X eth0 equal 16  Répartition # de manière uniforme sur 16 files d'attente

Si nécessaire, j'adapte les champs de hachage. Pour TCP4 avec des quadruplets (s = adresse IP source, d = adresse IP de destination, f = port source, n = port de destination) :

ethtool -N eth0 rx-flow-hash tcp4 sdfn
ethtool -N eth0 rx-flow-hash udp4 sdfn
ethtool -N eth0 rx-flow-hash tcp6 sdfn
ethtool -N eth0 rx-flow-hash udp6 sdfn

Certains pilotes permettent également de définir sa propre clé RSS (par exemple, pour une meilleure diffusion dans certains cas particuliers) :

ethtool -X eth0 hkey   # uniquement si le pilote/la carte réseau le prend en charge

Configurer correctement l'affinité du processeur et le NUMA

Je mappe chaque file d'attente RX via Affinité IRQ aux cœurs dédiés, en tenant compte de la structure NUMA, afin que les données transitent sur une courte distance via le contrôleur mémoire. Si la carte réseau (NIC) se trouve sur le nœud 0, j’affecte également les files d’attente principales aux cœurs du nœud 0 et je place les charges de travail à proximité. Cette proximité réduit les accès à distance et diminue considérablement les latences mémoire. À cet effet, il est utile de disposer d’un profil pour les files d’attente de production ainsi que de cœurs distincts pour les tâches de gestion et de déchargement. Ceux qui souhaitent approfondir le sujet trouveront des conseils pour un réglage fin sous Affinité IRQ, ce qui complique la planification par Noyau simplifiée.

Guide pratique sur l'affinité IRQ : des IRQ à un mappage stable des cœurs

Je commence par déterminer quelles IRQ correspondent aux files d'attente RX, puis je les lie de manière fixe :

grep -E "eth0.*Rx" /proc/interrupts
cat /sys/class/net/eth0/device/numa_node

Je définis cette affectation via smp_affinity_list, pour ne pas avoir à calculer de masques hexadécimaux. Exemple : files d'attente RX 0 à 7 sur les cœurs 2 à 9 :

Exemple # : attribuer des IRQ aux cœurs 2 à 9 (une ligne par IRQ)
echo 2  > /proc/irq//smp_affinity_list
echo 3  > /proc/irq//smp_affinity_list
echo 4  > /proc/irq//smp_affinity_list
...
echo 9  > /proc/irq//smp_affinity_list

Important : MSI-X doit être activé pour que chaque file d'attente dispose de ses propres interruptions. Si j'utilise le pinning manuel, je bloque irqbalance pour ces IRQ (par exemple via une liste noire) ou désactive le service de manière ciblée sur les hôtes à structure statique. Je vérifie également la configuration NUMA avec lscpu et l'affectation PCIe, afin de ne pas créer de chemins entre nœuds.

Configuration des fonctions de hachage et protocoles

Je définis les champs de hachage de manière à ce que les véritables Trafic- Répartir correctement les requêtes, plutôt que de les concentrer sur quelques files d’attente. Pour TCP/UDP, j’utilise le quadruplet ; pour IPv6, je procède de manière similaire, tandis que pour VXLAN ou GRE, je prends en compte des champs supplémentaires liés à l’encapsulation. Certaines cartes réseau proposent des clés de hachage configurables, que j’adapte à la charge de travail dominante. Dès que je constate une concentration de charge sur certaines files d’attente, j’ajuste le choix des clés de hachage. Cette étape ne prend que peu de temps, mais permet d’éviter une déséquilibre avec un nombre élevé de connexions.

Coalescence des interruptions et PPS

J'associe le RSS à une utilisation modérée Coalescence d'interruption, afin de regrouper le trafic à forte intensité PPS en lots gérables. Cela réduit la surcharge liée aux interruptions, mais ne doit pas pour autant augmenter la latence des services sensibles. C'est pourquoi je mesure les temps aller-retour et modifie progressivement les valeurs de coalescing. Ceux qui gèrent des charges de stockage ou de sauvegarde peuvent regrouper les données de manière plus marquée que dans le cas des API de couche 7 ou de la VoIP. En résumé, j’équilibre Latence par rapport au débit, jusqu'à ce que les deux concordent.

La coalescence en pratique : profils et points de mesure

Je commence par des paramètres par défaut modérés et je cherche progressivement le réglage optimal pour chaque charge de travail. Voici trois profils de départ qui ont fait leurs preuves :

  • API/Faible latence : 2 à 6 rx-usecs, rx-frames 16–32, désactivé (adaptatif)
  • Polyvalent : 8 à 16 rx-usecs, rx-frames 32–64, adaptatif à
  • Vente en gros/Stockage : 24 à 48 rx-usecs, rx-frames 128–256, adaptatif à
ethtool -c eth0
ethtool -C eth0 rx-usecs 12 rx-frames 64 adaptive-rx on

Pour cela, je mesure les latences p95/p99, le PPS, la charge CPU par cœur et les retransmissions. Dès que je constate une augmentation de la variance au niveau de l'API/VoIP, je passe à rx-usecs à nouveau vers le bas. Pour le stockage, je préfère augmenter la capacité par trames afin d'économiser des interruptions.

RSS dans des environnements à 10 Gbit

Sur les cartes réseau 10G, je travaille généralement avec 8 à 16 Queues de billard par port, à condition que le processeur dispose d'un nombre suffisant de cœurs. Les serveurs web, les passerelles de stockage et les hôtes de virtualisation s'adaptent ainsi parfaitement à un grand nombre de connexions parallèles. J'affecte les files d'attente principales aux cœurs libres, puis je mesure le PPS, la latence et les retransmissions. En cas de pertes de paquets, je vérifie le coalescing, le hachage et le taux d'utilisation par file d'attente. Ensuite, j'affine les paramètres affinité, jusqu'à ce que la charge de travail semble répartie de manière homogène.

RSS dans des configurations 25 Gbit et Multi-25G

À 25 Gbit/s, le PPS et la charge du bus augmentent, c'est pourquoi je NUMA- Je veille davantage à disposer d'un nombre suffisant de files d'attente et à respecter rigoureusement les délestages. Le Large Receive Offload (LRO) ou le RSC peuvent réduire la pression des paquets sur la pile, à condition que les applications le tolèrent. Je vérifie également les voies PCIe afin d'exclure tout goulot d'étranglement en dehors du réseau. Sur les hôtes disposant de plusieurs liaisons 25G, je sépare strictement les files d’attente et l’affinité en fonction des tâches et des nœuds. Ainsi, j’utilise Bande passante et les cœurs de manière efficace, sans générer de trafic inter-nœuds.

Détails sur le matériel et les pilotes : ce à quoi je fais attention

Toutes les cartes réseau ne se comportent pas de la même manière. Les générations Intel (par exemple ixgbe, i40e, ice) offrent des fonctionnalités telles que Flow Director/ATR, qui associent de manière ciblée les flux à des files d’attente – ce qui est utile lorsque je souhaite lisser les pics de trafic. La carte Mellanox mlx5 prend en charge aRFS au niveau matériel, ce qui réduit la charge du processeur lorsque la pile gère de nombreux sockets. Je décide au cas par cas d’activer ou non ces fonctionnalités et je mesure si elles améliorent la répartition. Sur les systèmes de routage/NAT, je désactive souvent LRO et je privilégie GRO pour préserver la cohérence des en-têtes ; sur des charges de travail purement serveur, LRO/GRO peut aider à atténuer la pression PPS. Il est également important de disposer d'un nombre suffisant de vecteurs MSI-X par file d'attente et de versions de firmware correctes.

RSS dans la virtualisation et les conteneurs

Dans l'hyperviseur, je combine des ressources physiques RSS- Des files d'attente avec des vNIC prenant en charge le multi-queue, comme virtio-net, afin que les machines virtuelles ne subissent pas de goulots d'étranglement artificiels. Je veille à l’affectation des cœurs de processeur (CPU-pinning) des machines virtuelles et je définis la proximité NUMA de leurs vCPU par rapport à la carte réseau physique. Ainsi, les données restent en local et l’hôte paie moins cher pour les accès en mémoire. Pour les conteneurs, j’affecte les pods critiques à des cœurs adaptés et je veille à ce que les files d’attente de l’hôte restent exemptes de charge parasite. Cet ordre améliore la Efficacité dans le cadre des microservices, où de nombreux petits flux sont générés.

Bien utiliser les technologies SR-IOV et VF-RSS

Avec SR-IOV, j'attribue à chaque machine virtuelle ses propres VF, qui peuvent à leur tour fournir plusieurs files d'attente et RSS. Je prévois suffisamment de VF par port, je veille à la capacité MSI-X et j'affecte les IRQ des VF dans la machine virtuelle en fonction de leurs vCPU. Dans les machines invitées Linux, j'active explicitement le mode multi-file d'attente, sinon la vNIC reste souvent à un seul niveau :

# dans l'invité (exemple virtio-net)
ethtool -l eth0
ethtool -L eth0 combined 4

Je répartis rigoureusement les hôtes dotés de plusieurs VF par nœud NUMA et par charge de travail, afin que les machines virtuelles ne se gênent pas mutuellement sur les mêmes chemins de réception physiques.

Monitoring et recherche d'erreurs

Je surveille le taux d'utilisation par Queue, les cœurs isolés, les pertes de paquets et les retransmissions, afin de détecter rapidement les anomalies. Lorsqu’un cœur se détache et que les autres restent inactifs, cela signifie souvent que l’affinité ou le nombre de files d’attente n’est pas correct. Dans ce cas, je vérifie successivement les champs de hachage, les masques d’IRQ et les valeurs de coalescing. De plus, je vérifie les Charge SoftIRQ, car elle fournit des indications sur des effets d'éviction. Ce n'est que lorsque ces signaux semblent stables que j'augmente le trafic ou que j'étends Queues de billard continue.

RPS, RFS et XPS : extensions logicielles du format RSS

Si une carte réseau ne dispose que de quelques files d'attente ou si j'utilise le bonding ou le tunneling, je complète RSS avec RPS (Receive Packet Steering) et RFS (Receive Flow Steering). RPS répartit les SoftIRQ entre les cœurs, tandis que RFS associe les flux au cœur sur lequel le socket correspondant est actif. J'active ces deux fonctions de manière ciblée :

# Augmenter le nombre global d'entrées de flux (RFS)
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries

# Définir le nombre de processeurs par file d'attente RX pour RPS (masque d'exemple, à adapter !)
for f in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo ffff > "$f"; done

Configurer la table de flux par file d'attente RX pour RFS (#)
for f in /sys/class/net/eth0/queues/rx-*/rps_flow_cnt; do echo 4096 > "$f"; done

Côté TX, j'utilise XPS (Transmit Packet Steering), afin que les paquets sortants soient envoyés par le nœud central qui les a générés :

for f in /sys/class/net/eth0/queues/tx-*/xps_cpus; do echo ffff > "$f"; done

Les RPS/RFS/XPS sollicitent un peu le processeur, mais s'avèrent utiles lorsque je manque de files d'attente au niveau matériel ou lorsque je souhaite respecter strictement la localisation des sockets.

Performances en flux unique, GRO/TSO et interrogation en temps réel

Un flux unique reste lié à un cœur, et ce pour une bonne raison. Si je souhaite augmenter la bande passante d'un flux unique, je mise sur les déchargements (GRO/TSO), une fréquence de cœur élevée et une coalescence adaptée. Pour les chemins où la latence est critique, on peut Busy-Polling aider :

Définir une valeur faible pour # et effectuer la mesure
sysctl -w net.core.busy_read=25
sysctl -w net.core.busy_poll=25

Le « busy polling » réduit les changements de contexte, mais mobilise du temps CPU. Je ne l'active que lorsque les latences p99 sont importantes, et je vérifie toujours ses effets sur la charge globale et la latence de queue. En règle générale, je désactive le GRO sur les serveurs ; j’utilise le LRO en fonction du rôle de chaque nœud ; pour les middleboxes, je reste prudent afin de ne pas perturber le traitement des en-têtes et la cohérence des hachages.

Recommandations et exemples : files d'attente, affinité, commandes

Comme point de départ, je choisis un nombre de files d'attente qui correspond à la CPU Si cela convient, observez ensuite la charge par file d'attente et ajustez-la par paliers. Pour 10G, 8 à 16 files d'attente suffisent souvent ; pour 25G, je pars souvent d'un nombre plus élevé, à condition que les cœurs soient disponibles. Pour l’affinité, j’utilise des masques clairs par IRQ, afin de pouvoir analyser plus facilement les chemins par la suite. Le tableau suivant fournit des valeurs indicatives synthétiques, que je vérifie ensuite par des mesures. Ce n’est qu’après analyse des résultats de mesure que je décide si je continuer augmenter ou réduire.

Vitesse de connexion Files d'attente RX typiques Exemples de commandes Remarques
10 Gbit/s 8-16 ethtool -l eth0 | ethtool -L eth0 rx 16 Coalescence Rester modéré, vérifier la latence L7
25 Gbit/s 16–32+ grep . /proc/interrupts | Masques d'IRQ via echo NUMA À noter : vérifier le nombre de voies PCIe
Multi-25G Par port, séparément Activer le vNIC multi-file d'attente (par exemple, virtio) Files d'attente par cœur et Charges de travail diviser

Ces valeurs indicatives ne constituent qu'un point de départ, et non un objectif, car les charges de travail varient considérablement. Je consigne les modifications, j'effectue des mesures avant et après l'ajustement et je laisse l'environnement inchangé pour le reste. Dès que le système reste stable sous la charge de production, je fige la configuration. Par la suite, je renouvelle les mesures après chaque mise à jour du noyau ou des pilotes. C'est ainsi que je m'assure que RSS une exécution sans faille et des résultats fiables et reproductibles.

Problèmes courants et solutions

Trop peu Queues de billard Certains cœurs sont surchargés ; un nombre trop élevé augmente la charge administrative et nuit au taux de réussite du cache. Une affinité mal choisie redirige les interruptions vers des cœurs déjà sollicités ou vers des nœuds NUMA inappropriés. De même, un hachage inadapté entraîne un engorgement des files d’attente par des flux dominants. Je résous cela étape par étape : ajuster le nombre de files d’attente, corriger l’affinité, étendre les champs de hachage, affiner le coalescing. Je documente chaque modification avec Métriques, avant de passer au levier suivant.

Scénarios concrets

Un serveur de stockage équipé d'une connexion 10G tire rapidement parti d'une capacité de 8 à 12 Queues de billard avec une coalescence modérée, afin d'assurer le bon déroulement des transferts en masse. Un serveur API gérant un nombre élevé de connexions nécessite souvent des champs de hachage plus fins et une latence réduite au niveau des interruptions. Les hôtes de virtualisation gagnent nettement en performance lorsque la fonctionnalité vNIC Multi-Queue est activée côté invité et qu’elle correspond à la configuration de l’hôte. Les charges de travail des conteneurs fonctionnent mieux lorsque les pods critiques s’exécutent à proximité de la carte réseau et de la mémoire NUMA. J’étends ces modèles en fonction de la situation en PPS, comparer les retransmissions et la répartition des files d'attente.

L'avantage des plateformes performantes

Configurations d'hébergement avec un RSS, les cartes réseau multi-files d'attente et une affinité bien gérée offrent des réserves notables en cas de pics de charge. Lors de l'évaluation d'offres de serveurs, il convient de s'informer spécifiquement sur la prise en charge multi-files d'attente, le NUMA-Pinning et la surveillance. Un fournisseur qui met clairement en œuvre ces éléments obtient souvent des courbes de débit nettement meilleures. Pour des solutions de serveurs et d’hébergement performantes, je recommande sans hésiter webhoster.de. Cette orientation porte ses fruits en Performance et une grande stabilité, notamment en cas de nombreux flux parallèles.

Résumé pour la pratique

J'active Recevoir Side Scaling : je définis un nombre raisonnable de files d’attente, j’affecte les IRQ aux cœurs appropriés et je vérifie la configuration du hachage. Ensuite, j’optimise le coalescing en fonction de la latence, je veille à la proximité NUMA et je répartis les charges de travail de manière cohérente. En virtualisation, j’utilise le multi-file d’attente jusque dans les machines invitées et je synchronise le pinning et l’affinité. Les mesures relatives au PPS, à la charge des files d’attente, aux retransmissions et à la latence déterminent la prochaine étape. En procédant ainsi, on exploite pleinement les débits 10G et 25G, tout en conservant Latence dans ce cadre et génère de manière fiable un rendement de réseau.

Derniers articles

Rack de serveurs avec des modules de mémoire vive mis en évidence pour illustrer le cache ARC de ZFS dans un centre de données
Serveurs et machines virtuelles

Cache ARC de ZFS : bien comprendre l'utilisation de la mémoire

Découvrez comment fonctionne le cache ARC de ZFS, pourquoi une consommation élevée de RAM est normale et comment régler correctement l'utilisation de la mémoire pour améliorer les performances de ZFS.