Unité centrale du serveur Les classes d'ordonnanceur contrôlent quel processus reçoit du temps de calcul et quand, et comment les priorités déclenchent le refoulement, afin que les temps de réponse restent faibles et que le débit reste calculable. Je montre comment les classes, Priorités et les tranches horaires interagissent et comment je dirige de manière ciblée la répartition de la charge avec quelques réglages.
Points centraux
- Classes de l'ordonnanceur ordonnent les charges de travail selon des règles et influencent le temps de réaction.
- Priorités décider qui obtient du temps CPU en premier et qui attend.
- Préemption supprime les tâches en cours d'exécution lorsque des tâches plus importantes sont en attente.
- Équité empêche que certains processus dominent durablement.
- Mesure rend les effets visibles et conduit à de meilleurs réglages.
Pourquoi les classes d'ordonnanceurs déterminent les performances des serveurs
Dans les environnements de production, les serveurs web, les bases de données et les jobs sont en concurrence pour les mêmes CPUs, C'est pourquoi une attribution réglementée est décisive. Je mise sur des classes claires pour que les demandes interactives ne soient pas reléguées au second plan et que les actions des utilisateurs reçoivent des réponses rapides. Une répartition claire des services dans les classes réduit les temps d'attente, diminue les temps morts et rend le comportement prévisible, même en cas de pics de charge. Sans cette classification, le risque augmente qu'un processus gourmand en CPU ne vienne perturber les services sans que l'on s'en rende compte. Temps de réponse de tous les autres. Je donne donc la priorité aux chemins critiques pour l'entreprise, car c'est précisément là que chaque milliseconde compte.
Principes de base : priorité, classes, tranches horaires
Chaque ordonnanceur combine Priorité, des classes et des tranches de temps pour allouer du temps de calcul et contrôler le refoulement. Une priorité plus élevée réduit les temps d'attente, mais des valeurs trop élevées excluent d'autres processus, ce qui donne l'impression de bégayer. Les tranches de temps limitent le temps de calcul d'un processus avant que le suivant ne prenne le relais, ce qui favorise l'équité. Les classes définissent en outre si une tâche est traitée en priorité, uniformément ou avec des règles de délai. J'évalue ces leviers ensemble, car seule la combinaison permet d'atteindre l'ensemble des objectifs. Planification reflète de manière réaliste.
CFS en détail : vruntime, granularité et fenêtre de latence
Avec Linux-CFS ne compte pas le temps réel, mais le temps d'exécution virtuel (vruntime) d'une tâche. Plus une tâche a reçu de CPU, plus son vruntime augmente et plus elle est replanifiée tard. Ce mécanisme crée Équité, mais peut générer des latences très différentes en fonction du nombre de threads actifs. Le site Fenêtre de latence (sched_latency) détermine la durée pendant laquelle CFS alloue „équitablement“ du temps à toutes les tâches exécutables. Pour un grand nombre de tâches, CFS raccourcit la granularité minimale par tâche, afin que tout le monde y passe une fois - avec pour effet secondaire une augmentation des changements de contexte. Avec peu de tâches, les quanta et donc le débit des tâches lourdes augmentent.
Je ne fais que des ajustements délicats : une légère augmentation des min_granularité lisse les tempêtes de changement de contexte pour des milliers de threads de travail actifs. Une version légèrement plus grande wakeup_granularity empêche les tâches à durée de vie courte fraîchement réveillées de préempter les threads qui s'exécutent trop souvent. Je teste les modifications séparément pour les profils de pointe de jour et de charge, car le même réglage a soudain des effets très différents sous charge de nuit.
Les classes de l'ordonnanceur Linux expliquées brièvement
Sous Linux, les classes séparent les tâches typiques du serveur en Règles et les attentes, afin que les tâches interactives ne soient pas éclipsées par les longues tâches de calcul. CFS sert les processus généraux de manière équitable, tandis que les classes temps réel s'adressent à des objectifs de réaction dure et que DEADLINE assure une protection plus précise des délais. Des classes spéciales comme Idle ou Batch couvrent les tâches d'arrière-plan sans perturber les services de premier plan. Pour chaque service, je vérifie quelle classe correspond à son modèle de communication au lieu de me contenter de modifier les valeurs de Nice. Ceux qui souhaitent aller plus loin trouveront des informations pratiques sur CFS et alternatives, Nous avons mis en place une série d'outils qui ont fait leurs preuves dans le domaine de l'hébergement.
| Classe | Utilisation typique | Propriété | Risque en cas de mauvaise configuration |
|---|---|---|---|
| CFS (SCHED_OTHER) | Généralités Services | Juste valeur par échéance | Les skieurs de fond évincent subtilement les emplois plus légers |
| En temps réel (SCHED_FIFO/RR) | Latence critique Tâches | Modèle préféré | Starvation possible pour les processus CFS |
| DEADLINE | Des délais stricts | Réservé CPU par budget/période | Le manque de budget entraîne des abandons |
| Batch/Idle | Sauvegardes, analyses | Courir quand il reste du temps | Augmentation de la durée de fonctionnement en cas de charge élevée |
Systemd, cgroups et outils pour la mise en œuvre
Je fixe des priorités non seulement ad hoc, mais aussi en Units et cgroups afin que les règles restent stables : CPUSchedulingPolicy et CPUSchedulingPriority contrôlent la classe et la priorité d'un service, CPUWeight/CpuQuota allouent les cœurs de manière équitable. Dans cgroup v2, j'utilise cpu.max et cpu.weight, pour combiner un cadre dur (quota/burst) et une pondération douce. Ainsi, un chemin de réponse reste rapide, tandis que les backfills ou les rapports reçoivent de la puissance de manière fiable sans s'effondrer.
Pour des corrections ponctuelles, je m'aide nice/renice (pondération CFS), chrt (attributs temps réel/DEADLINE), taskset (affinité avec le CPU) et ionice (priorité d'E/S). J'intègre cela dans les scripts de démarrage au lieu de faire des ajustements manuels. Important : je ne mets en temps réel que des fonctions partielles bien définies - par exemple un log-flusher - et laisse le reste dans le CFS, afin que l'ensemble du système stable reste.
Fixer des priorités de manière judicieuse : Guide pratique
Je commence avec des taux modérés Priorités et j'augmente progressivement les valeurs tout en surveillant la latence, les sauts de CPU et les changements de contexte. Les travailleurs frontaux ont une priorité légèrement plus élevée afin que les requêtes n'attendent pas derrière les rapports, mais je laisse de la place pour les threads de la base de données. Je déplace les tâches de traitement par lots vers des heures creuses ou je les assigne à des classes de traitement par lots/d'inactivité afin de libérer les heures de pointe. Pour les objectifs de réaction difficiles, je vérifie si une petite partie clairement délimitée dans des classes en temps réel est judicieuse, sans que l'ensemble du système ne soit mis sous pression. Je présente une procédure structurée dans ce guide sur la Optimisation des priorités, qui décrit les changements progressifs et les points de mesure.
Effets sur la latence et le débit
Les priorités élevées réduisent Latence de requêtes interactives, mais ils suppriment du temps de calcul pour les tâches d'arrière-plan. Des tranches de temps équilibrées empêchent qu'un seul travailleur n'occupe trop longtemps le CPU et que les files d'attente n'enflent. Selon la charge de travail, les quanta courts augmentent la réactivité, tandis que les quanta longs favorisent le débit en cas de streaming ou de compression. Je mesure donc les deux : 95e et 99e percentiles des temps de réponse ainsi que les requêtes traitées par seconde. Ces indicateurs me permettent de savoir quand je dois redéfinir les priorités ou les tranches de temps. calibrer.
NUMA, affinité et contrôle d'interruption
Sur les systèmes à plusieurs socles, je décide consciemment de NUMA-appartenance et Affinité avec le CPU. Je lie les services sensibles à la latence à des noyaux au sein d'un nœud NUMA et je veille à ce que leur mémoire soit allouée localement. J'évite ainsi les accès distants avec une latence supplémentaire. Dans le cas d'hôtes chargés de bases de données, je sépare les threads OLTP et la maintenance en arrière-plan (par exemple les pointeurs de contrôle) sur différents groupes de cœurs, afin que les transactions à courte durée de vie ne se disputent pas les cœurs avec des tâches à long terme.
Voir aussi Interruptions jouent un rôle : je laisse irqbalance fonctionner, mais j'exclue les noyaux hot-path si nécessaire. J'attribue les interruptions réseau (RX/TX) à plusieurs cœurs afin que la pile réseau ne devienne pas un goulot d'étranglement. Pour les services très sensibles à la latence, je déplace les sources d'interruption bruyantes sur leurs propres noyaux. Cette séparation spatiale complète les priorités et les classes - elle ne les remplace pas.
Monitoring et métriques : prendre des décisions avec des données
J'évalue Métriques comme la charge CPU, la longueur de la file d'attente d'exécution, le changement de contexte et le steal CPU, afin d'attribuer clairement les goulots d'étranglement. Des files d'attente d'exécution croissantes alors que le débit diminue indiquent des priorités erronées ou des tranches de temps trop étroites. Un nombre inhabituel de changements de contexte révèle que les threads calculent trop court et que la gestion elle-même consomme du temps. Pour les charges mixtes, je vérifie les mesures d'équité afin qu'aucune classe de service ne soit perdante à long terme. Une bonne introduction aux directives et aux pondérations est fournie par cette contribution à Politiques d'ordonnancement, J'utilise ce rapport comme base de décision.
Traçage, profilage et tests reproductibles
Avant de me fixer sur le tuning, je veux voir la cause et l'effet. J'utilise Profilage et Traçage, pour mettre en évidence les hotpaths, les temps d'attente de verrouillage et la fréquence de préemption. Des tests de charge courts et répétables avec une phase de réchauffement évitent les erreurs d'interprétation dues aux caches froids ou aux JIT de réchauffement. Je collecte des percentiles sur plusieurs minutes et plusieurs exécutions, au lieu de comparer uniquement des valeurs de pointe. Il est important de faire une séparation nette : d'abord la baseline, puis un changement, puis un test identique. Je documente les mesures intermédiaires avec les paramètres de l'hôte et du noyau afin de pouvoir recréer exactement le même environnement des semaines plus tard.
Pièges et anti-patterns typiques
J'augmente Priorités jamais de manière globale pour des services entiers, car cela ne fait que déplacer la hiérarchie et créer de nouveaux goulets d'étranglement. Des valeurs temps réel élevées en permanence entraînent facilement la starification de processus normaux et génèrent des effets secondaires imprévisibles. Des tranches de temps trop petites poussent les changements de contexte à la hausse, la performance diminue, bien que le CPU travaille apparemment. Un mélange de tâches liées à l'unité centrale et de tâches chargées d'E/S sans choix de classe clair gaspille les performances en alternance. Procéder de manière systématique permet de gagner du temps, d'éviter les retours en arrière et de maintenir les Stabilité haut.
SMT, états d'énergie et effets turbo
SMT/hyper-threading double les noyaux logiques, mais divise les unités d'exécution physiques. Je planifie donc de préférence les threads critiques pour la latence sur différents cœurs physiques avant d'occuper leurs cœurs frères SMT. Sinon, la logique de calcul partagée peut allonger les temps d'attente. En outre, je surveille Turbo- et États CLes états de sommeil profond permettent d'économiser de l'énergie, mais coûtent du temps de réveil. Sur les chemins de latence, je réduis les C-States profonds ou je garde les noyaux „au chaud“, si la politique énergétique le permet. Inversement, je laisse délibérément les classes de lots dormir plus profondément - elles bénéficient de l'efficacité sans freiner les utilisateurs.
Exemples d'ajustement par type de charge de travail
Pour les serveurs web, je mets en place des priorité-pour les gestionnaires de requêtes et laisser les processus de mise en cache s'exécuter juste en dessous. Les bases de données bénéficient de tranches de temps équilibrées, d'un nombre suffisant de threads de travail actifs et d'une utilisation en temps réel limitée aux log-flushers ou aux checkpointers. Je place les tâches de traitement par lots dans des classes Idle/Batch afin qu'elles utilisent des cycles libres sans ralentir les chemins frontaux. Je sépare les analyses et l'ETL des services interactifs, souvent par classe propre ou par conteneur avec des quotas CPU. De cette manière, je maîtrise la latence sans avoir recours à des Matériel informatique de l'entreprise.
Rollouts, guardrails et voies de retour
J'effectue le réglage de l'ordonnanceur comme une release : avec Canary-hôtes, des critères d'interruption clairs et un retour en arrière rapide. Je définis des seuils pour la latence P99, le taux d'erreur et le steal CPU. Si une valeur dépasse le seuil, je reviens automatiquement à la dernière configuration stable. Je limite les modifications par itération : seulement les priorités ou seulement les tranches de temps - jamais les deux en même temps. Je conserve une version de tous les paramètres et je documente les hypothèses et les résultats de mesure. Ainsi, le chemin vers une bonne configuration reste compréhensible, même si les personnes ou les plateformes changent.
Virtualisation et hôtes partagés
Sur les hôtes partagés, je contrôle CPU-Quotas, épinglage et affinité NUMA avant de peaufiner les priorités. Les machines virtuelles partagent des cœurs physiques, c'est pourquoi le steal CPU modifie considérablement les temps d'attente mesurés. Je prévois des réservations pour les services critiques afin que leurs threads puissent bénéficier d'un temps de calcul planifiable. Je lie les conteneurs à des limites afin d'éviter l'escalade par des clients individuels. Ce n'est qu'une fois cette base établie que je peux affiner l'attribution des classes et la gestion des données. Priorité par processus.
Résumé pour la vie quotidienne
J'attribue d'abord les services à des classes et de fixer des priorités modérées et d'observer de manière ciblée la latence, le débit et les files d'attente. Les petits pas produisent des effets clairs, les grands sauts masquent les causes et rendent les retours en arrière difficiles. Là où le temps de réaction compte, j'autorise une préférence limitée ; là où le débit compte, je prolonge les quanta et j'aplatis les priorités. Ce sont les valeurs mesurées qui guident chaque décision, pas l'intuition, car les ordonnanceurs donnent facilement des résultats non intuitifs. Avec cette discipline, j'utilise les Serveur-CPU efficace, maintient des réponses rapides et une véritable équité entre tous les services.


