Sous Linux, IRQ Balance gère la répartition des interruptions matérielles entre les cœurs du processeur et détermine ainsi si la charge réseau est répartie de manière uniforme ou si certains cœurs sont ralentis. Je vais t'expliquer comment utiliser irqbalance de manière ciblée, quand passer à l'affinité IRQ manuelle et quels paramètres choisir sur les serveurs à forte charge du réseau qui comptent vraiment.
Points centraux
Avant d’entrer dans les détails, je vais résumer les décisions les plus importantes qui m’ont toujours aidé dans les projets présentant une charge d’E/S élevée. Je considère que la répartition automatique via irqbalance constitue un bon point de départ ; j’évalue ensuite son efficacité et j’apporte des ajustements ciblés. Pour les charges de travail déterministes, j’affecte manuellement certaines IRQ à des cœurs spécifiques et j’exclus les autres processeurs de la répartition automatique. Je tiens compte très tôt de la proximité NUMA, car elle réduit la latence et garantit le débit. Grâce à une surveillance claire, j’identifie plus rapidement les goulots d’étranglement et je les régule sans Risques.
Cette liste te montre les points auxquels je prête particulièrement attention lors de la configuration :
- Automatique Tout d'abord : activer irqbalance, mesurer son effet
- affinité de manière ciblée : verrouiller les IRQ critiques, réduire la gigue
- Processeurs interdits: Garder des cœurs libres pour les threads d'application
- NUMA Remarque : veillez à ce que les IRQ restent proches du nœud de mémoire
- Suivi: Vérifier /proc/interrupts et les latences
Les bases de l'IRQ expliquées en bref
Une demande d'interruption (IRQ) est un signal par lequel le matériel transmet du travail au processeur, interrompant ainsi une tâche en cours d'exécution. Si un nombre trop important de ces signaux parvient au même cœur, la charge de travail de celui-ci augmente et son temps de réponse devient lent, tandis que d'autres cœurs restent inutilisés ; c'est exactement ce que je souhaite éviter avec Distribution éviter. irqbalance répartit ces IRQ de manière dynamique entre plusieurs cœurs et évalue l'état du système à intervalles réguliers. Je commence par consulter /proc/interrupts et je vérifie dans les colonnes le nombre d'IRQ reçues par CPU. Si certaines colonnes deviennent trop chargées, j'interviens activement pour réguler et réduire ainsi les Points chauds.
Répartition automatique avec irqbalance
Sur les distributions modernes, je démarre avec le service irqbalance, qui ajuste par défaut la répartition des IRQ à intervalles réguliers. Je l'active à l'aide de la commande systemctl enable --now irqbalance et je vérifie l'état avant d'intervenir plus en profondeur ; c'est ainsi que j'exploite les ressources existantes Automatique. Les fichiers de configuration se trouvent, selon le système, dans /etc/sysconfig/irqbalance ou /etc/default/irqbalance, où je peux exclure des processeurs ou des IRQ. La variable est particulièrement utile IRQBALANCE_BANNED_CPUS sous forme de masque 64 bits, afin de réserver des cœurs définis pour les applications. Si vous souhaitez approfondir vos connaissances à l'aide d'exemples pratiques, vous trouverez ici une introduction concise à la Performances du réseau, que je cite souvent lors d'ateliers et que j'utilise dans le cadre de projets.
Mettre en œuvre l'affinité IRQ manuelle en toute sécurité
Lorsque les charges de travail sont très sensibles à la gigue ou que certains cœurs doivent rester exclusivement réservés aux processus de l'espace utilisateur, je configure manuellement l'affinité IRQ. Pour ce faire, j'écris des masques de bits dans /proc/irq/NUMÉRO_D'IRQ/smp_affinity et je définis sur quels cœurs une interruption peut s'exécuter ; cela permet une meilleure planification Conduite. Je commence par déterminer les numéros d'IRQ concernés à l'aide de grep dans /proc/interrupts. Pour les périphériques réseau, j'affecte souvent les files d'attente RX/TX à des cœurs proches des threads de l'application, tout en laissant d'autres cœurs libres. Ce bref article fournit de bonnes explications sur cette approche Guide sur l'affinité IRQ, que j'utilise régulièrement comme point de départ.
Le tableau suivant présente les masques de bits courants et leur signification. J'utilise ces exemples pour définir rapidement des configurations avec un minimum d'erreurs, puis pour vérifier leur effet à l'aide de /proc/interrupts à vérifier.
| Objectif | Exemple de masque (hex) | noyaux | Commentaire |
|---|---|---|---|
| Uniquement CPU0 | 0x1 | 0 | Test simple, faible dispersion |
| Uniquement CPU1 | 0x2 | 1 | Sépare les IRQ du CPU0, réduit Interférence |
| CPU0–CPU1 | 0x3 | 0-1 | Réparti sur deux cœurs, léger Décharge |
| CPU2–CPU3 | 0xC | 2-3 | Utile lorsque la valeur est comprise entre 0 et 1 pour les threads d'application libre restent |
| CPU0–CPU3 | 0xF | 0–3 | Répartition large sur 4 cœurs, mélange Dernier |
Mesure : lire correctement /proc/interrupts
J'ouvre le fichier /proc/interrupts et je vois, sur chaque ligne, une IRQ ainsi que, dans chaque colonne, les compteurs par processeur ; cela met immédiatement en évidence les déséquilibres visible. Lorsqu’une colonne augmente nettement plus vite que les autres, la charge s’y concentre. Je vérifie alors quel pilote est impliqué et si RSS/RPS a déjà réparti la charge. De plus, je lance temporairement irqbalance en avant-plan avec un affichage de débogage afin de comprendre ses décisions et d’éviter toute erreur d’appréciation. Après chaque modification, je vérifie à nouveau les compteurs et je mesure la latence sous charge, afin de pouvoir étayer les effets observés et d’éviter toute Risques peut éviter.
Isolation du CPU et masques d'exclusion
Je mets IRQBALANCE_BANNED_CPUS, afin d'exclure systématiquement certains noyaux de la répartition automatique ; je libère ainsi des ressources pour les threads d'application. Dans les configurations plus récentes, j'utilise en outre IRQBALANCE_BANNED_IRQS, lorsque certains appareils doivent fonctionner de manière autonome sur un noyau ; cela réduit les interférences pour les systèmes sensibles Charges de travail. Dans les scénarios à faible latence, je désactive délibérément irqbalance et j'attribue les IRQ de manière statique afin d'éviter toute redistribution qui pourrait perturber le fonctionnement. Si vous souhaitez mieux comprendre l'attribution des IRQ par le processeur, vous trouverez des informations utiles sur le sujet Gestion des interruptions sur les serveurs. L'essentiel reste de commencer par mesurer, puis de définir les paramètres et de vérifier à nouveau l'effet obtenu, afin d'éviter les surprises dans le Exploitation d'éviter.
Aspects NUMA et proximité
Sur les systèmes NUMA, je veille à diriger autant que possible les IRQ vers les cœurs du nœud NUMA dans la mémoire duquel se trouvent les données concernées ; cela réduit la latence et augmente Débit. Je combine cela avec l'affinité CPU pour l'application, afin que les threads et les interruptions s'exécutent localement les uns par rapport aux autres. irqbalance fonctionne bien sur NUMA, mais j'ajuste si nécessaire à l'aide de masques d'exclusion. Il est essentiel de ne pas répartir la charge entre les nœuds lorsque celle-ci peut de toute façon être conservée localement. En préservant cette proximité, on bénéficie de temps de réponse constants et on préserve de précieuses Cache-Ressources.
Cours intensif sur les réseaux : RSS, RPS/RFS et XPS
Avant d'affiner les masques d'IRQ, je vérifie les fonctionnalités de la carte réseau (NIC), telles que le RSS, ainsi que les mécanismes du noyau, comme le RPS/RFS et le XPS ; ceux-ci influencent fortement la répartition des paquets. Le RSS répartit déjà les interruptions de file d’attente entre plusieurs cœurs, tandis que le RPS/RFS façonne le traitement au sein du noyau et que le XPS structure les chemins d’émission ; cela permet d’éviter les Points chauds. Je synchronise ces mécanismes avec ma stratégie d’IRQ afin qu’ils ne se contredisent pas. Lorsque les files d’attente, les affinités d’IRQ et l’affinité des applications sont bien coordonnées, les E/S réseau fonctionnent nettement mieux. Je procède ensuite à de nouvelles mesures en conditions réelles avant de poursuivre Étapes je place.
MSI-X, Multi-Queue et une structure de file d'attente épurée
De nombreuses cartes réseau 10–100G utilisent le mode MSI-X et fournissent des vecteurs d'interruption distincts pour chaque file d'attente RX/TX. Je commence par vérifier avec ethtool -l eth0 (nombre de chaînes) et /proc/interrupts, combien de files d'attente sont réellement actives et quels sont leurs noms (par exemple,. eth0-TxRx-0, eth0-TxRx-1). L'objectif est d'adapter le nombre de files d'attente au nombre de cœurs utilisés par nœud NUMA et de les fixer de manière déterministe. Avec ethtool -L eth0 combined N Je configure le nombre de files d'attente ; ensuite, j'organise les IRQ générées via smp_affinity aux cœurs appropriés. Je veille à ce que les paires RX/TX d’une même file d’attente soient affectées au même cœur ou, au moins, au même socket, afin que Localité du cache s'applique. Important : je vérifie directement dans /proc/interrupts et en effectuant un bref test de charge (pps/débit) avant de poursuivre l'optimisation.
Coalescence des interruptions et budget NAPI
C'est surtout lorsque le débit de paquets est élevé que les valeurs de coalescence influencent l'efficacité de ma stratégie IRQ. Avec ethtool -c eth0 je vois si rx-usecs et rx-frames sont définies. Une coalescence plus importante réduit le nombre d’IRQ par seconde et soulage le processeur, mais augmente la latence et la gigue. Je procède à des ajustements prudents : par petits pas, en mesurant à chaque fois (latence p95/p99 et charge du processeur). Du côté de l’émetteur, cela a pour effet tx-usecs analogique. Parallèlement, je mets à l'échelle le comportement NAPI via net.core.netdev_budget et net.core.netdev_budget_usecs, si NET_RX commence à s'accumuler dans les SoftIRQ. Si les pertes augmentent dans /proc/net/softnet_stat, j'augmente le budget à titre d'essai ou je répartis les files d'attente RX de manière plus cohérente ; si la latence du système devient trop importante, je réduis ces paramètres. Je tiens compte de l’interaction entre GRO/LRO et TSO/GSO : une agrégation excessive réduit la charge des IRQ, mais peut générer des pics de latence – je les compense en fonction du profil d’application.
Lecture transparente des SoftIRQ
Outre les HardIRQ, je gère la charge des SoftIRQ. Avec cat /proc/softirqs j'observe NET_RX et NET_TX par CPU ; si certaines colonnes prédominent, cela entraîne une charge de travail excessive dans les threads ksoftirqd. Un top -H montre-moi rapidement lesquels ksoftirqd/N Les noyaux pèsent lourd. Je mesure plus en profondeur avec perf top ou courts perf record Exécuter pour identifier les points chauds dans le pilote ou le traitement de la pile. Lorsque les threads ksoftirqd deviennent actifs (au lieu d’un traitement immédiat dans le contexte IRQ), la latence augmente souvent de manière significative ; je réagis alors en améliorant la répartition des files d’attente, en augmentant le budget NAPI ou en affectant de manière ciblée les threads ksoftirqd concernés à un processeur spécifique via taskset -pc. Important : je consigne ces modifications, car leurs effets sont subtils et j'ai besoin de pouvoir revenir rapidement en arrière en cas de doute.
Tirer pleinement parti de la technologie SMT/Hyper-Threading et de la topologie
Avec SMT activé, je partage un cœur physique avec deux processeurs logiques. Je vérifie les relations entre frères via lscpu -e et /sys/devices/system/cpu/cpuX/topology/thread_siblings_list. Pour les chemins sensibles à la latence, j’évite de placer le thread de l’application et l’IRQ associée sur le même cœur physique (différents threads SMT) ; ils se disputent en effet les unités d’exécution et les caches. Je privilégie les paires dans lesquelles, par exemple, un thread d’application s’exécute sur le CPU2 et la file d’attente RX associée sur le CPU3 (autre cœur physique, même nœud NUMA). Si le SMT perturbe la cohérence, je planifie plutôt avec moins de cœurs physiques, mais exclusifs, ce qui m’évite les fluctuations Interférences.
Virtualisation : KVM, vhost et SR-IOV
Dans les environnements virtualisés, je considère séparément l’hôte et l’invité. Sur l’hôte, je répartis soigneusement les IRQ des cartes réseau physiques entre les cœurs du nœud NUMA correspondant. Si l’invité utilise virtio-net, des IRQ supplémentaires sont générées pour les threads vhost ; je les détecte dans /proc/interrupts et j'affecte de manière cohérente les workers vhost aux files d'attente de la carte réseau physique. Au niveau de l'invité, je configure également les affinités RSS/XPS et IRQ, dans la mesure où le pilote virtio fournit plusieurs files d'attente. Avec SR-IOV, il est judicieux d’attribuer à chaque invité une ou plusieurs VF avec leurs propres vecteurs MSI-X et de les épingler au sein de l’invité ; cette isolation améliore la latence et la prévisibilité. Je m’en tiens à un schéma clair : les vCPU de l’invité sur des pCPU dédiés, les IRQ associées sur des cœurs proches, et ne pas mélanger les threads de l’émulateur/vhost avec les threads d’applications gourmands en ressources de calcul – ainsi, le chemin des données reste planifiable.
Fréquence du processeur, états C et optimisation NOHZ
Les latences IRQ en pâtissent lorsque les cœurs entrent dans des états C profonds ou fonctionnent à un rythme soutenu. Pour les charges de travail sensibles, je règle le régulateur du processeur sur performance (cpupower frequency‑set -g performance) et je réduis les états C profonds via les options de démarrage ou les pilotes afin de limiter les temps de réveil. Sur les serveurs fortement sollicités, cela a souvent un effet plus positif que n’importe quel réglage fin des affinités. Dans les profils de latence très exigeants, j’ajoute nohz_full= et rcu_nocbs= pour les cœurs isolés, afin d’éviter que le Tick-Timer et les rappels RCU n’interfèrent ; je définis délibérément les CPU de gestion interne séparément. Je teste toutefois ces modifications séparément, car elles peuvent avoir des effets secondaires sur l’ordonnancement et la consommation d’énergie. L’essentiel reste de comparer rigoureusement les valeurs mesurées avant et après la modification, sinon je me retrouve à Optimisations dans le noir.
Systemd, les Cgroups et l'isolation des applications
Outre le « pinning » des IRQ, je sépare les threads des applications à l'aide des Cgroups et de l'affinité systemd. Via CPUAffinity= Dans les fichiers Unit et les contrôleurs de CPU (cgroup v2), j'attribue des cœurs fixes aux services. Cela m'évite que, du côté du planificateur, des threads ne se glissent sur les processeurs que j'ai réservés aux IRQ. Dans les environnements de conteneurs, je configure cpuset.cpus et vérifie cpuset.cpus.effective, afin que les engagements en matière de ressources soient réellement respectés. Important : IRQBALANCE_BANNED_CPUS ne contrôle que les cas où irqbalance ne répartit pas les IRQ ; les threads du noyau, tels que ksoftirqd, continuent de suivre le planificateur. Pour obtenir une isolation stricte, j'ai donc besoin d'une combinaison d'affinités IRQ, d'affinités CPU des services et, le cas échéant, de noyaux isolés. Ainsi, le chemin de données et l'application restent clairement séparés et la Dernier ne s'immisce pas de manière incontrôlée.
Erreurs courantes et solutions
Je ne désactive jamais « irqbalance » de manière générale sans connaître les profils de charge ; sinon, les IRQ se concentrent rapidement sur quelques cœurs. Il est tout aussi déconseillé d'ouvrir tous les cœurs à toutes les IRQ, alors que les threads sensibles sont exclusifs Ressources . Autre erreur : ne pas tester les modifications de manière isolée et ne pas en mesurer les effets ; on ne sait donc pas clairement ce qui est réellement efficace. Je tiens également compte des paires d’Hyper-Threading : il vaut mieux que le thread de l’application et l’IRQ associée ne partagent pas le même cœur physique. Je documente chaque étape et je crée des points de restauration afin de pouvoir revenir rapidement à la dernière bon Je reviens à la configuration.
Liste de contrôle pratique pour les serveurs
Je commence toujours par établir une base de référence : activer irqbalance, mesurer la charge du système, surveiller /proc/interrupts et mesurer les latences ; ce n’est qu’ensuite que je modifie les paramètres. Dans un deuxième temps, je termine par IRQBALANCE_BANNED_CPUS Je sélectionne les cœurs qui doivent rester réservés aux threads d'application ; cela me permet d'éviter les interférences IRQ inutiles. Ensuite, je configure les IRQ critiques via smp_affinity sur quelques cœurs bien choisis et je veille à respecter la proximité NUMA. Ensuite, je vérifie les paramètres RSS/RPS/RFS et XPS, ainsi que les options de déchargement de la carte réseau, afin de répartir la charge de manière optimale. Pour finir, je procède à des tests en conditions de charge de production, je compare les indicateurs et je ne conserve que les modifications dont l'efficacité a été démontrée agissent.
Fichiers de configuration et commandes systemd
J'active le service à l'aide de systemctl enable --now irqbalance et vérifie avec systemctl status irqbalance la durée ; c'est ainsi que je définis le Service certainement prêt. Dans /etc/sysconfig/irqbalance ou /etc/default/irqbalance je mets IRQBALANCE_BANNED_CPUS ainsi que, en option, IRQBALANCE_BANNED_IRQS. J'applique les modifications avec systemctl restart irqbalance et surveille en parallèle les compteurs dans /proc/interrupts. Pour les tests, j'utilise le mode « foreground » d'irqbalance afin de suivre les décisions en temps réel. Ce n'est qu'une fois que j'ai compris le comportement que j'intègre définitivement les ajustements dans le fichier Configuration.
Quand je désactive irqbalance
Dans les configurations en temps réel ou pour les applications extrêmement sensibles à la latence, j’arrête irqbalance et j’attribue les IRQ de manière statique afin qu’aucune redistribution ne vienne perturber le fonctionnement. J’isole les cœurs pour ces charges de travail et je laisse délibérément les IRQ de trafic s’exécuter sur d’autres cœurs ; ainsi, les threads d’application restent planifiable. Même dans le cas d’environnements de locataires strictement séparés, cette approche est intéressante, car elle permet de réduire les interférences entre les machines virtuelles ou les conteneurs. Si certains pilotes fonctionnent moins bien avec le mode automatique, j’exclue leurs IRQ via une liste noire. Dès que les profils de charge redeviennent plus variables, j’active à nouveau irqbalance et je vérifie l’effet avec de nouvelles Valeurs mesurées.
En bref
Je commence par lancer irqbalance, j'évalue les effets et j'effectue des ajustements ciblés, plutôt que d'intervenir à l'aveuglette partout ; cela me permet de garder une vue d'ensemble du système et Transparence. Pour les charges de travail sensibles, j'attribue des IRQ adaptées, j'isole les cœurs pour les applications et je respecte la proximité NUMA. À l'aide de masques d'interdiction, je contrôle les zones dans lesquelles irqbalance est autorisé à intervenir et j'empêche les déplacements indésirables. Je vérifie régulièrement /proc/interrupts, la latence et le débit, afin que les modifications soient étayées par des données fiables. En procédant ainsi, on exploite pleinement le potentiel d’IRQ Balance et on maintient les serveurs sous une charge réseau nettement réactif.


