
Bonjour ! Je voudrais expliquer simplement la mécanique d'apparition du steal à l'intérieur des machines virtuelles et quelques artefacts non évidents que nous avons pu découvrir lors de son étude, dans laquelle j'ai dû m'immerger en tant que directeur technique de la plateforme cloud. . La plateforme fonctionne sur KVM.
Le temps de steal du CPU est le temps pendant lequel la machine virtuelle ne reçoit pas de ressources processeur pour son exécution. Ce temps n'est pris en compte que dans les systèmes d'exploitation invités dans des environnements de virtualisation. Les raisons de la perte de ces ressources dédiées, comme dans la vie, sont assez nébuleuses. Mais nous avons décidé de nous pencher sur la question, et nous avons même effectué une série d'expériences. Ce n'est pas que nous savons tout sur le steal maintenant, mais nous allons partager quelques éléments intéressants.
1. Qu'est-ce que le steal
Ainsi, le steal est une métrique qui indique le manque de temps processeur pour les processus à l'intérieur de la machine virtuelle. Comme décrit , le steal est le temps pendant lequel l'hyperviseur exécute d'autres processus sur le système d'exploitation hôte, bien qu'il ait mis le processus de la machine virtuelle en attente d'exécution. En d'autres termes, le steal se calcule comme la différence entre le temps où le processus est prêt à être exécuté et le temps où des ressources processeur lui sont effectivement attribuées.
La métrique de steal est fournie à la machine virtuelle par l'hyperviseur. Cependant, l'hyperviseur ne précise pas quels autres processus il exécute, il se contente de dire : « tant que je suis occupé, je ne peux pas te donner de temps ». Sur KVM, le support du calcul du steal a été ajouté dans Il y a deux points clés ici :
- La machine virtuelle apprend le steal de l'hyperviseur. Ainsi, en termes de pertes, pour les processus sur la machine virtuelle elle-même, c'est une mesure indirecte qui peut être soumise à diverses distorsions.
- L'hyperviseur ne partage pas avec la machine virtuelle des informations sur ce avec quoi il est occupé — le principal point est qu'il ne lui accorde pas de temps. En raison de cela, la machine virtuelle elle-même ne peut pas identifier les distorsions dans le chiffre du steal qui pourraient être évaluées en fonction de la nature des processus concurrents.
2. Qu'est-ce qui influence le steal
2.1. Calcul du steal
En fait, le steal est calculé à peu près de la même manière que le temps d'utilisation normal du processeur. Il n'y a pas beaucoup d'information sur la façon dont l'utilisation est calculée. Peut-être parce que la plupart des gens considèrent cette question comme évidente. Mais il y a aussi des pièges. Pour se familiariser avec ce processus, vous pouvez lire : vous apprendrez beaucoup de subtilités lors du calcul de l'utilisation et des situations où ce calcul peut être erroné pour les raisons suivantes :
- Surchauffe du processeur, entraînant des cycles manqués.
- Activation/désactivation du turbo boost, modifiant ainsi la fréquence d'horloge du processeur.
- Changement de la durée du quantum de temps, se produisant lors de l'utilisation de technologies d'économie d'énergie pour le processeur, telles que SpeedStep.
- Problème du calcul moyen : estimer l'utilisation à 80 % durant une minute peut masquer un pic ponctuel à 100 %.
- Le verrouillage cyclique (spin lock) conduit à ce que le processeur soit utilisé, mais le processus utilisateur ne voit pas d'avancement dans son exécution. En conséquence, le taux d'utilisation du processeur par le processus sera de 100 %, alors que le temps processeur physique ne sera pas consommé.
Je n'ai pas trouvé d'articles décrivant un tel calcul pour le steal (si vous en connaissez, partagez-le en commentaires). Mais, d'après les sources, le mécanisme de calcul est le même que pour l'utilisation. Un autre compteur est juste ajouté dans le noyau, spécifiquement pour le processus KVM (processus de machine virtuelle), qui compte la durée pendant laquelle le processus KVM est resté en attente de temps processeur. Le compteur obtient des informations sur le processeur à partir de ses spécifications et vérifie si tous ses ticks ont été utilisés par le processus de la machine virtuelle. Si oui, nous considérons que le processeur s'occupait uniquement du processus de la machine virtuelle. Sinon, nous informons qu'il était occupé par autre chose, et du coup, du steal apparaît.
Le processus de calcul du steal est soumis aux mêmes problèmes que le calcul normal de l'utilisation. Ce n'est pas à dire que ces problèmes apparaissent souvent, mais ils semblent décourageants.
2.2. Types de virtualisation sur KVM
En général, il existe trois types de virtualisation, tous pris en charge par KVM. Le type de virtualisation peut affecter le mécanisme d'apparition du steal.
Translating. Dans ce cas, le fonctionnement du système d'exploitation de la machine virtuelle avec les dispositifs physiques de l'hyperviseur se passe comme suit :
- Le système d'exploitation invité envoie une commande à son dispositif invité.
- Le pilote du dispositif invité reçoit la commande, prépare une requête pour le BIOS du dispositif et l'envoie à l'hyperviseur.
- Le processus de l'hyperviseur traduit une commande en une commande pour l'appareil physique, la rendant ainsi, entre autres, plus sécurisée.
- Le pilote de l'appareil physique reçoit la commande modifiée et l'envoie déjà à l'appareil physique lui-même.
- Les résultats de l'exécution des commandes reviennent par le même chemin.
L'avantage de la traduction est qu'elle permet d'émuler n'importe quel appareil et ne nécessite pas de préparation spéciale du noyau du système d'exploitation. Mais cela a un coût, principalement en termes de performances.
Virtualisation matérielle. Dans ce cas, l'appareil comprend au niveau matériel les commandes du système d'exploitation. C'est la méthode la plus rapide et la plus efficace. Mais, malheureusement, elle n'est pas prise en charge par tous les appareils physiques, hyperviseurs et systèmes d'exploitation invités. Actuellement, les principaux dispositifs qui prennent en charge la virtualisation matérielle sont les processeurs.
Paravirtualisation. C'est la variante de virtualisation la plus courante sur KVM et le mode de virtualisation le plus répandu pour les systèmes d'exploitation invités. Sa particularité est que l'interaction avec certaines sous-systèmes de l'hyperviseur (par exemple, le réseau ou la pile de disques) ou l'allocation de pages mémoire se fait via l'API de l'hyperviseur, sans traduction des commandes de bas niveau. Le inconvénient de cette méthode de virtualisation est la nécessité de modifier le noyau du système d'exploitation invité, afin qu'il puisse interagir avec l'hyperviseur à travers cette API. Mais cela est généralement résolu par l'installation de pilotes spéciaux sur le système d'exploitation invité. Dans KVM, cette API s'appelle .
En paravirtualisation, par rapport à la traduction, le chemin vers l'appareil physique est considérablement raccourci grâce à l'envoi de commandes directement de la machine virtuelle au processus de l'hyperviseur sur l'hôte. Cela permet d'accélérer l'exécution de toutes les instructions à l'intérieur de la machine virtuelle. Dans KVM, cela est géré par l'API virtio, qui ne fonctionne que pour certains dispositifs, tels que l'adaptateur réseau ou le disque. C'est pourquoi des pilotes virtio sont installés à l'intérieur des machines virtuelles.
La contrepartie de cette accélération est que tous les processus exécutés à l'intérieur de la machine virtuelle ne restent pas à l'intérieur. Cela crée certains effets secondaires qui peuvent entraîner des problèmes de contournement. Je recommande de commencer l'étude approfondie de cette question par .
2.3. La planification « équitable »
La machine virtuelle sur l'hyperviseur est, en fait, un processus ordinaire qui suit les lois de la planification (allocation des ressources entre les processus) dans le noyau Linux, c'est pourquoi nous allons l'examiner plus en détail.
Linux utilise ce qu'on appelle le CFS, Completely Fair Scheduler, devenu le gestionnaire par défaut depuis le noyau 2.6.23. Pour comprendre cet algorithme, vous pouvez lire l'architecture du noyau Linux ou les sources. L'idée principale du CFS est d'allouer le temps processeur entre les processus en fonction de la durée de leur exécution. Plus un processus nécessite de temps processeur, moins de ce temps il reçoit. Cela garantit une exécution « équitable » de tous les processus — pour qu'un processus ne monopolise pas constamment tous les processeurs, et que les autres processus puissent également s'exécuter.
Parfois, cette approche conduit à des artefacts intéressants. Les anciens utilisateurs de Linux se souviennent sûrement du gel d'un éditeur de texte ordinaire sur le bureau lors du lancement d'applications gourmandes en ressources comme un compilateur. Cela se produisait parce que les tâches peu gourmandes des applications de bureau rivalisaient avec des tâches consommant activement des ressources, telles que le compilateur. Le CFS considère cela comme injuste, c'est pourquoi il arrête périodiquement l'éditeur de texte et donne au processeur le temps de traiter les tâches du compilateur. Cela a été corrigé grâce au mécanisme , mais de nombreuses autres spécificités de l'allocation du temps processeur entre les tâches subsistent. En réalité, il ne s'agit pas de l'échec du CFS, mais d'une tentative d'attirer l'attention sur le fait que l'allocation « équitable » du temps processeur n'est pas une tâche triviale.
Un autre point important dans le planificateur est la préemption. C'est nécessaire pour évincer un processus gourmand du processeur et permettre à d'autres de travailler. Le processus d'éviction s'appelle le changement de contexte, c'est-à-dire le basculement du contexte du processeur. À ce moment-là, tout le contexte de la tâche est sauvegardé : l'état de la pile, les registres, etc., après quoi le processus est mis en attente, et un autre prend sa place. C'est une opération coûteuse pour le système d'exploitation, et elle est rarement utilisée, mais en soi, il n'y a rien de mauvais là-dedans. Un changement de contexte fréquent peut indiquer un problème dans le système d'exploitation, mais généralement, il se déroule en continu et n'indique rien de particulier.
Une telle longue explication est nécessaire pour illustrer un fait : plus un processus essaie de consommer des ressources processeur dans un planificateur Linux équitable, plus il sera rapidement arrêté afin que d'autres processus puissent également travailler. Que ce soit juste ou non est une question complexe, qui se résout différemment selon les charges. Jusqu'à récemment, dans Windows, le planificateur était orienté vers le traitement prioritaire des applications de bureau, ce qui pouvait entraîner des blocages pour les processus en arrière-plan. Dans Sun Solaris, il y avait cinq classes différentes de planificateurs. Lorsque la virtualisation a été lancée, une sixième a été ajoutée. , car les cinq précédents fonctionnaient de manière inadéquate avec la virtualisation des Zones Solaris. Je recommande de commencer par une étude détaillée de ce sujet avec des livres comme ou .
2.4. Comment surveiller le steal ?
Surveiller le steal à l'intérieur d'une machine virtuelle, comme toute autre métrique processeur, est simple : on peut utiliser n'importe quel outil de collecte de métriques processeur. L'essentiel est que la machine virtuelle soit sur Linux. Windows, pour une raison inconnue, ne fournit pas cette information à ses utilisateurs. 🙁

Sortie de la commande top : détails de la charge processeur, dans la dernière colonne à droite — steal
La difficulté survient lors de la tentative d'obtenir ces informations depuis l'hyperviseur. On peut essayer de prévoir le steal sur la machine hôte, par exemple, à partir de la moyenne de charge (LA) — une valeur moyenne du nombre de processus en attente dans la file d'attente d'exécution. La méthode de calcul de ce paramètre est complexe, mais en gros, si la LA normalisée par le nombre de threads du processeur est supérieure à 1, cela indique que le serveur sous Linux est quelque peu surchargé.
Que attendent donc tous ces processus ? La réponse évidente est le processeur. Mais cette réponse n'est pas tout à fait correcte, car parfois le processeur est libre et la LA est élevée. Rappelez-vous, Il en va de même pour le disque et d'autres dispositifs d'entrée/sortie. En réalité, les processus peuvent attendre la fin de tout type de blocage, qu'il soit physique, lié à un dispositif d'entrée/sortie, ou logique, comme un mutex. Cela inclut également les blocages au niveau matériel (ce que renvoie le disque) ou logique (ce qu'on appelle les primitives de blocage, comprenant de nombreuses entités telles que les mutex adaptatifs et spin, les sémaphores, les variables de condition, les verrouillages en lecture/écriture, les verrouillages IPC…).
Une autre particularité de la LA est qu'elle est calculée comme une moyenne à travers le système d'exploitation. Par exemple, 100 processus se disputent un fichier, et là, LA=50. Une valeur aussi élevée semble indiquer que l'OS ne va pas bien. Mais pour certains codes mal écrits, cela peut être un état normal, où seul ce code est en difficulté, tandis que d'autres processus du système d'exploitation ne souffrent pas.
À cause de cette moyenne (de pas moins d'une minute), définir quoi que ce soit sur la base de l'indicateur LA est une tâche difficile, avec des résultats très incertains dans des cas précis. Si vous essayez de comprendre, vous découvrirez que les articles sur Wikipédia et d'autres ressources disponibles ne décrivent que les cas les plus simples, sans expliquer en profondeur le processus. Tous ceux qui s'y intéressent, je les renvoie encore une fois, — par le biais des liens. Pour ceux qui préfèrent le français — .
3. Effets spéciaux
Nous allons maintenant nous concentrer sur les principaux cas de steal que nous avons rencontrés. Je vais expliquer comment ils découlent de tout ce qui a été dit précédemment et comment ils se rapportent aux indicateurs sur l'hyperviseur.
Reutilisation. C'est le cas le plus simple et le plus fréquent : l'hyperviseur est surutilisé. En effet, de nombreuses machines virtuelles sont en cours d'exécution, une forte consommation de processeurs à l'intérieur d'elles, une grande concurrence, et une utilisation selon la LA supérieure à 1 (normalisée en fonction des threads de processeur). À l'intérieur de toutes les machines virtuelles, tout est au ralentissement. Le steal transmis par l'hyperviseur augmente également, il faut redistribuer la charge ou éteindre quelqu'un. En somme, tout cela est logique et compréhensible.
Paravirtualisation contre instances isolées. Sur l'hyperviseur, il n'y a qu'une seule machine virtuelle qui consomme une petite partie de ses ressources, mais qui impose une forte charge en entrée/sortie, par exemple, sur le disque. Et d'une manière ou d'une autre, un léger steal apparaît dans celle-ci, jusqu'à 10 % (comme le montrent plusieurs expériences menées).
C'est un cas intéressant. Le steal apparaît ici précisément à cause des blocages au niveau des pilotes paravirtualisés. À l'intérieur de la machine virtuelle, une interruption est créée, est traitée par le pilote et se dirige vers l'hyperviseur. En raison du traitement de l'interruption sur l'hyperviseur, cela semble être une requête envoyée pour la machine virtuelle, qui est prête à s'exécuter et attend le processeur, mais elle ne reçoit pas de temps processeur. La machine virtuelle pense que ce temps a été volé.
Cela se produit au moment de l'envoi du tampon, qui quitte l'espace noyau de l'hyperviseur, et nous commençons à l'attendre. Pourtant, du point de vue de la machine virtuelle, il devrait revenir immédiatement. Par conséquent, selon l'algorithme de calcul du steal, ce temps est considéré comme volé. Il est probable que dans cette situation, d'autres mécanismes puissent aussi être à l'œuvre (par exemple, le traitement d'autres appels systèmes), mais ils ne devraient pas différer beaucoup.
Planificateur contre machines virtuelles à forte charge. Lorsque qu'une machine virtuelle subit plus de steal que d'autres, c'est justement lié au planificateur. Plus le processus sollicite le processeur, plus le planificateur l'expulsera rapidement pour que les autres puissent également travailler. Si la machine virtuelle consomme peu de ressources, elle ne remarquera presque pas le steal : son processus était simplement en attente, il faut lui donner plus de temps. Si la machine virtuelle génère une charge maximale sur tous ses cœurs, elle est expulsée plus souvent du processeur et on essaie de ne pas lui donner trop de temps.
C'est encore pire lorsque des processus au sein de la machine virtuelle essaient d'acquérir plus de puissance processeur car ils ont du mal à traiter les données. Dans ce cas, le système d'exploitation sur l'hyperviseur, grâce à une optimisation juste, tendra à accorder de moins en moins de temps processeur. Ce processus se déroule de manière exponentielle et le steal grimpe en flèche, bien que les autres machines virtuelles puissent à peine le remarquer. Et plus il y a de cœurs, plus la machine sous pression en souffre. En résumé, les machines virtuelles à forte charge avec plusieurs cœurs sont les plus touchées.
LA faible, mais il y a du steal. Si le LA est d'environ 0,7 (c'est-à-dire que l'hyperviseur semble sous chargé), mais qu'il y a une observation de steal dans certaines machines virtuelles :
- La variante décrite ci-dessus avec la paravirtualisation. Une machine virtuelle peut recevoir des métriques indiquant un vol de temps CPU, même si tout va bien du côté de l'hyperviseur. D'après nos expériences, ce type de vol ne dépasse pas 10 % et ne devrait pas avoir d'impact significatif sur les performances des applications à l'intérieur de la machine virtuelle.
- Le paramètre LA est mal considéré. Plus précisément, à chaque moment précis, il est calculé correctement, mais lorsqu'il est moyenné sur une minute, il se retrouve sous-évalué. Par exemple, si une machine virtuelle utilise tous ses processeurs exactement pendant une demi-minute sur un tiers de l'hyperviseur, le LA pour cette minute sur l'hyperviseur sera de 0,15 ; quatre machines virtuelles de ce type fonctionnant simultanément donneront 0,6. Cependant, le fait qu'il y ait eu un vol énorme proche de 25 % sur chaque machine pendant une demi-minute ne pourra pas être récupéré.
- Encore une fois, à cause du planificateur, qui a décidé que quelqu'un mangeait trop et qu'il devait attendre. Pendant ce temps, je vais changer de contexte, traiter les interruptions et m'occuper d'autres choses système importantes. Au final, certaines machines virtuelles ne voient aucun problème, tandis que d'autres subissent une dégradation sérieuse des performances.
4. Autres distorsions
Il existe encore un million de raisons de distorsion dans la répartition équitable du temps CPU sur une machine virtuelle. Par exemple, l'hyperthreading et NUMA compliquent les calculs. Ils rendent le choix de cœur pour l'exécution d'un processus encore plus confus, car le planificateur utilise des coefficients — des poids, qui compliquent encore le calcul lors du changement de contexte.
Des distorsions peuvent également se produire à cause de technologies comme le turbo boost ou, au contraire, le mode économie d'énergie, qui peuvent artificiellement augmenter ou diminuer la fréquence ou même le quantum de temps sur le serveur lors du calcul de l'utilisation. L'activation du turbo boost réduit les performances d'un thread processeur en raison de l'augmentation des performances d'un autre. À ce moment, l'information sur la fréquence actuelle du processeur n'est pas transmise à la machine virtuelle, qui pense que son temps est volé (par exemple, elle a demandé 2 GHz, mais en reçoit deux fois moins).
En général, il peut y avoir de nombreuses raisons de distorsions. Dans un système spécifique, vous pouvez déceler d'autres éléments. Il vaut mieux commencer par les livres dont j'ai fourni les liens ci-dessus et par la collecte de statistiques à partir de l'hyperviseur avec des outils comme perf, sysdig, systemtap, qui sont .
5. Conclusions
- Une certaine quantité de steal peut survenir en raison de la paravirtualisation, et cela peut être considéré comme normal. Sur internet, on mentionne que ce chiffre peut atteindre 5 à 10 %. Cela dépend des applications à l'intérieur de la machine virtuelle et de la charge qu'elles imposent à leurs dispositifs physiques. Il est important de prêter attention à la manière dont les applications se comportent à l'intérieur des machines virtuelles.
- Le rapport entre la charge sur l'hyperviseur et le steal à l'intérieur de la machine virtuelle n'est pas toujours clairement corrélé ; les deux évaluations du steal peuvent être erronées dans des situations spécifiques lors de différentes charges.
- Le planificateur n'est pas bienveillant envers les processus qui demandent beaucoup. Il essaie de donner moins à ceux qui demandent plus. Les grandes machines virtuelles sont un mal.
- Un petit steal peut être normal même sans paravirtualisation (teneur compte de la charge à l'intérieur de la machine virtuelle, des caractéristiques des charges voisines, de la répartition des charges par threads et d'autres facteurs).
- Si vous souhaitez déterminer le steal dans un système spécifique, il faut examiner différentes options, collecter des métriques, les analyser soigneusement et réfléchir à la manière de répartir uniformément la charge. Des écarts peuvent se produire dans tous les cas, et ils doivent être validés par des expériences ou en consultant le débogueur du noyau.
Source : habr.com
