Steal : qui vole le temps processeur des machines virtuelles

Steal : qui vole le temps processeur des machines virtuelles

Bonjour! Je veux vous parler en termes simples des mécanismes de vol à l'intérieur des machines virtuelles et de certains artefacts non évidents que nous avons réussi à découvrir au cours de nos recherches, dans lesquels j'ai dû me plonger en tant que directeur technique d'une plateforme cloud. Solutions Cloud Mail.ru. La plateforme fonctionne sur KVM.

Le temps de vol du processeur 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 les environnements de virtualisation. Les raisons pour lesquelles ces ressources les plus allouées vont, comme dans la vie, sont très vagues. Mais nous avons décidé de le comprendre et avons même mené un certain nombre d'expériences. Ce n’est pas que nous sachions tout sur le vol, mais nous allons maintenant vous dire quelque chose d’intéressant.

1. Qu'est-ce que le vol

Ainsi, le vol est une métrique qui indique un manque de temps processeur pour les processus à l'intérieur d'une machine virtuelle. Comme décrit dans le patch du noyau KVMLa furtivité est le temps pendant lequel l'hyperviseur exécute d'autres processus sur le système d'exploitation hôte même s'il a mis en file d'attente le processus de la machine virtuelle pour son exécution. Autrement dit, le vol est calculé comme la différence entre le moment où le processus est prêt à s'exécuter et le moment où le temps processeur est alloué au processus.

Le noyau de la machine virtuelle reçoit la métrique de vol de l'hyperviseur. Dans le même temps, l'hyperviseur ne précise pas exactement quels autres processus il exécute, il dit simplement « tant que je suis occupé, je ne peux pas vous donner de temps ». Sur KVM, la prise en charge du calcul de vol a été ajoutée à correctifs. Il y a deux points clés ici :

  • La machine virtuelle apprend le vol auprès de l'hyperviseur. Autrement dit, du point de vue des pertes, pour les processus sur la machine virtuelle elle-même, il s'agit d'une mesure indirecte qui peut être sujette à diverses distorsions.
  • L'hyperviseur ne partage pas d'informations avec la machine virtuelle sur ce qu'il fait d'autre - l'essentiel est qu'il n'y consacre pas de temps. Pour cette raison, la machine virtuelle elle-même ne peut pas détecter les distorsions de l'indicateur de vol, qui pourraient être évaluées par la nature des processus concurrents.

2. Qu'est-ce qui affecte le vol

2.1. Calcul de vol

Essentiellement, le vol est calculé à peu près de la même manière que le temps d'utilisation normal du processeur. Il n’existe pas beaucoup d’informations sur la manière dont le recyclage est envisagé. Probablement parce que la plupart des gens considèrent cette question comme évidente. Mais il y a aussi des pièges ici. Pour vous familiariser avec ce processus, vous pouvez lire article de Brendan Gregg: vous découvrirez de nombreuses nuances lors du calcul de l'utilisation et des situations dans lesquelles ce calcul sera erroné pour les raisons suivantes :

  • Le processeur surchauffe, provoquant des sauts de cycles.
  • Activez/désactivez le turbo boost, qui modifie la vitesse d'horloge du processeur.
  • Modification de la durée de la tranche de temps qui se produit lors de l'utilisation de technologies d'économie d'énergie du processeur telles que SpeedStep.
  • Le problème du calcul de la moyenne : estimer une utilisation d’une minute à 80 % peut cacher une rafale à court terme de 100 %.
  • Un spin lock entraîne la récupération du processeur, mais le processus utilisateur ne voit aucune progression dans son exécution. En conséquence, l'utilisation calculée du processeur par le processus sera de cent pour cent, bien que le processus ne consomme pas physiquement de temps processeur.

Je n'ai pas trouvé d'article décrivant un calcul similaire pour le vol (si vous le savez, partagez-le dans les commentaires). Mais à en juger par le code source, le mécanisme de calcul est le même que pour le recyclage. Simplement, un autre compteur est ajouté dans le noyau, directement pour le processus KVM (processus de machine virtuelle), qui compte la durée du processus KVM en attente du temps CPU. Le compteur extrait les informations sur le processeur de sa spécification et vérifie si tous ses ticks sont utilisés par le processus de la machine virtuelle. Si c’est tout, alors nous supposons que le processeur n’était occupé que par le processus de la machine virtuelle. Sinon, nous informons que le processeur faisait autre chose, un vol est apparu.

Le processus de comptage des vols est soumis aux mêmes problèmes que le comptage régulier des déchets recyclés. Cela ne veut pas dire que de tels problèmes apparaissent souvent, mais ils semblent décourageants.

2.2. Types de virtualisation sur KVM

D'une manière générale, il existe trois types de virtualisation, tous pris en charge par KVM. Le mécanisme d'occurrence du vol peut dépendre du type de virtualisation.

Diffusion. Dans ce cas, le fonctionnement du système d'exploitation de la machine virtuelle avec les périphériques hyperviseurs physiques se produit à peu près comme ceci :

  1. Le système d'exploitation invité envoie une commande à son appareil invité.
  2. Le pilote de périphérique invité reçoit la commande, génère une requête pour le BIOS du périphérique et l'envoie à l'hyperviseur.
  3. Le processus de l'hyperviseur traduit commande en commande pour le périphérique physique, le rendant, entre autres, plus sécurisé.
  4. Le pilote du périphérique physique accepte la commande modifiée et l'envoie au périphérique physique lui-même.
  5. Les résultats de l'exécution des commandes remontent par le même chemin.

L'avantage de la traduction est qu'elle permet d'émuler n'importe quel périphérique et ne nécessite pas de préparation particulière du noyau du système d'exploitation. Mais cela se paie avant tout en rapidité.

Virtualisation matérielle. Dans ce cas, l'appareil au niveau matériel comprend les commandes du système d'exploitation. C'est le moyen le plus rapide et le meilleur. Mais malheureusement, il n’est pas pris en charge par tous les appareils physiques, hyperviseurs et systèmes d’exploitation invités. Actuellement, les principaux appareils prenant en charge la virtualisation matérielle sont les processeurs.

Paravirtualisation. L'option la plus courante pour la virtualisation des appareils sur KVM et généralement le mode de virtualisation le plus courant pour les systèmes d'exploitation invités. Sa particularité est que le travail avec certains sous-systèmes de l'hyperviseur (par exemple, avec le réseau ou la pile de disques) ou l'allocation de pages de mémoire s'effectue à l'aide de l'API de l'hyperviseur, sans traduire les commandes de bas niveau. L'inconvénient de cette méthode de virtualisation est que le noyau du système d'exploitation invité doit être modifié pour qu'il puisse communiquer avec l'hyperviseur via cette API. Mais cela est généralement résolu en installant des pilotes spéciaux sur le système d'exploitation invité. Dans KVM, cette API s'appelle API Virtio.

Avec la paravirtualisation, par rapport à la diffusion, le chemin vers le périphérique physique est considérablement réduit en envoyant des commandes directement de la machine virtuelle au processus hyperviseur sur l'hôte. Cela vous permet d'accélérer l'exécution de toutes les instructions à l'intérieur de la machine virtuelle. Dans KVM, cela est effectué par l'API virtio, qui ne fonctionne que pour certains appareils, comme un adaptateur réseau ou un adaptateur de disque. C'est pourquoi les pilotes virtio sont installés dans les machines virtuelles.

L’inconvénient de cette accélération est que tous les processus exécutés à l’intérieur de la machine virtuelle n’y restent pas. Cela crée des effets spéciaux qui peuvent entraîner l'apparition d'un vol. Je recommande de commencer une étude détaillée de cette question avec Une API pour les E/S virtuelles : virtio.

2.3. Programmation « juste »

Une machine virtuelle sur hyperviseur est en fait un processus ordinaire qui obéit aux lois d’ordonnancement (répartition des ressources entre processus) du noyau Linux, regardons-le donc de plus près.

Linux utilise ce qu'on appelle CFS, Completely Fair Scheduler, qui est devenu le planificateur par défaut depuis le noyau 2.6.23. Pour comprendre cet algorithme, vous pouvez lire l'architecture du noyau Linux ou le code source. L'essence de CFS est de répartir le temps processeur entre les processus en fonction de la durée de leur exécution. Plus un processus nécessite de temps CPU, moins il en reçoit. Cela garantit que tous les processus sont exécutés « équitablement » - de sorte qu'un processus n'occupe pas constamment tous les processeurs et que d'autres processus puissent également s'exécuter.

Parfois, ce paradigme conduit à des artefacts intéressants. Les utilisateurs Linux de longue date se souviennent probablement du gel d'un éditeur de texte classique sur un bureau lors de l'exécution d'applications gourmandes en ressources telles qu'un compilateur. Cela s'est produit parce que les tâches peu gourmandes en ressources dans les applications de bureau étaient en concurrence avec des tâches gourmandes en ressources, telles que le compilateur. CFS pense que c'est injuste, c'est pourquoi il arrête périodiquement l'éditeur de texte et laisse le processeur gérer les tâches du compilateur. Cela a été corrigé à l'aide d'un mécanisme sched_autogroup, mais de nombreuses autres caractéristiques de répartition du temps processeur entre les tâches sont restées. En fait, il ne s'agit pas d'une histoire sur la façon dont tout va mal dans CFS, mais d'une tentative d'attirer l'attention sur le fait que la répartition « juste » du temps processeur n'est pas la tâche la plus triviale.

Un autre point important du planificateur est la préemption. Cela est nécessaire pour éliminer le processus de ricanement du processeur et laisser les autres travailler. Le processus d'éjection est appelé changement de contexte. Dans ce cas, tout le contexte de la tâche est conservé : l'état de la pile, les registres, etc., après quoi le processus est envoyé en attente, et un autre prend sa place. Il s’agit d’une opération coûteuse pour le système d’exploitation et rarement utilisée, mais elle n’a rien de mal en soi. Des changements de contexte fréquents peuvent indiquer un problème dans le système d'exploitation, mais ils sont généralement continus et n'indiquent rien de particulier.

Une si longue histoire est nécessaire pour expliquer un fait : plus un processus essaie de consommer de ressources processeur dans un planificateur Linux honnête, plus il sera arrêté rapidement afin que d'autres processus puissent également fonctionner. Que cela soit exact ou non est une question complexe qui peut être résolue différemment selon les charges. Sous Windows, jusqu'à récemment, le planificateur se concentrait sur le traitement prioritaire des applications de bureau, ce qui pouvait provoquer le blocage des processus en arrière-plan. Sun Solaris disposait de cinq classes différentes de planificateurs. Lorsque nous avons lancé la virtualisation, nous en avons ajouté une sixième, Planificateur de partage équitable, car les cinq précédents ne fonctionnaient pas correctement avec la virtualisation Solaris Zones. Je recommande de commencer une étude détaillée de cette question avec des livres comme Composants internes de Solaris : Solaris 10 et architecture du noyau OpenSolaris ou Comprendre le noyau Linux.

2.4. Comment surveiller le vol ?

La surveillance du vol à l'intérieur d'une machine virtuelle, comme toute autre métrique de processeur, est simple : vous pouvez utiliser n'importe quel outil de métrique de processeur. L'essentiel est que la machine virtuelle soit sous Linux. Pour une raison quelconque, Windows ne fournit pas ces informations à ses utilisateurs. 🙁

Steal : qui vole le temps processeur des machines virtuelles
Résultat de la commande supérieure : détails de la charge du processeur, dans la colonne la plus à droite - voler

La difficulté survient lorsqu’on tente d’obtenir ces informations auprès de l’hyperviseur. Vous pouvez essayer de prédire le vol sur la machine hôte, par exemple en utilisant le paramètre Load Average (LA) - la 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 n'est pas simple, mais en général, si LA normalisé par le nombre de threads du processeur est supérieur à 1, cela indique que le serveur Linux est surchargé de quelque chose.

Qu’attendent tous ces processus ? La réponse évidente est le processeur. Mais la réponse n'est pas tout à fait correcte, car parfois le processeur est libre, mais LA dépasse l'échelle. Souviens-toi comment NFS chute et comment LA se développe. La même chose peut se produire avec un disque et d’autres périphériques d’entrée/sortie. Mais en réalité, les processus peuvent attendre la fin de n'importe quel verrou, qu'il soit physique, associé à un périphérique d'E/S, ou logique, comme un mutex. Cela inclut également le verrouillage au niveau matériel (la même réponse du disque) ou logique (les soi-disant primitives de verrouillage, qui comprennent un tas d'entités, des mutex adaptatifs et spin, des sémaphores, des variables de condition, des verrous rw, des verrous ipc. ...).

Une autre caractéristique de LA est qu'il est considéré comme une moyenne de système d'exploitation. Par exemple, 100 processus sont en compétition pour un fichier, et alors LA=50. Une valeur aussi élevée semble indiquer que le système d’exploitation est mauvais. Mais pour d'autres codes mal écrits, cela peut être un état normal, malgré le fait qu'il est le seul à être mauvais et que les autres processus du système d'exploitation n'en souffrent pas.

En raison de cette moyenne (et en pas moins d'une minute), déterminer quoi que ce soit par l'indicateur LA n'est pas la tâche la plus gratifiante, avec des résultats très incertains dans des cas spécifiques. Si vous essayez de le comprendre, vous constaterez que les articles sur Wikipédia et d'autres ressources disponibles ne décrivent que les cas les plus simples, sans explication approfondie du processus. J'envoie encore une fois à tous ceux qui sont intéressés, ici pour Brendan Gregg  - suivez les liens ci-dessous. Qui est trop paresseux pour parler anglais - traduction de son article populaire sur Los Angeles.

3. Effets spéciaux

Voyons maintenant les principaux cas de vol que nous avons rencontrés. Je vais vous expliquer comment ils découlent de tout ce qui précède et comment ils se rapportent aux indicateurs de l'hyperviseur.

Recyclage. Le plus simple et le plus courant : l’hyperviseur a été réutilisé. En effet, il y a beaucoup de machines virtuelles en cours d'exécution, une consommation de processeur élevée à l'intérieur, beaucoup de concurrence, l'utilisation de LA est supérieure à 1 (normalisée par les threads du processeur). Tout à l'intérieur de toutes les machines virtuelles ralentit. Le vol transmis depuis l'hyperviseur augmente également, il faut redistribuer la charge ou éteindre quelqu'un. En général, tout est logique et compréhensible.

Paravirtualisation et instances uniques. Il n'y a qu'une seule machine virtuelle sur l'hyperviseur ; elle en consomme une petite partie, mais produit une charge d'E/S importante, par exemple sur disque. Et de quelque part, un petit vol apparaît, jusqu'à 10 % (comme le montrent plusieurs expériences).

Le cas est intéressant. Le vol apparaît ici précisément à cause du blocage au niveau des pilotes paravirtualisés. Une interruption est créée à l'intérieur de la machine virtuelle, traitée par le pilote et envoyée à l'hyperviseur. En raison de la gestion des interruptions sur l'hyperviseur, pour la machine virtuelle, cela ressemble à une requête envoyée, elle est prête à être exécutée et attend le processeur, mais le temps processeur ne lui est pas attribué. La fille virtuelle pense que ce temps a été volé.

Cela se produit au moment où le tampon est envoyé, il entre dans l'espace noyau de l'hyperviseur et nous commençons à l'attendre. Cependant, du point de vue de la machine virtuelle, il devrait revenir immédiatement. Par conséquent, selon l’algorithme de calcul du vol, ce temps est considéré comme volé. Très probablement, dans cette situation, il peut y avoir d'autres mécanismes (par exemple, le traitement d'autres appels système), mais ils ne devraient pas être très différents.

Planificateur versus machines virtuelles hautement chargées. Lorsqu'une machine virtuelle est plus victime de vol que d'autres, cela est dû au planificateur. Plus un processus charge le processeur, plus tôt le planificateur le supprimera afin que les autres puissent également fonctionner. Si la machine virtuelle consomme peu, elle ne sera guère volée : son processus est honnêtement resté assis et a attendu, nous devons lui donner plus de temps. Si une machine virtuelle produit la charge maximale sur tous ses cœurs, elle est souvent expulsée du processeur et ils essaient de ne pas lui consacrer beaucoup de temps.

C'est encore pire lorsque les processus à l'intérieur de la machine virtuelle tentent d'obtenir plus de processeur parce qu'ils ne peuvent pas gérer le traitement des données. Ensuite, le système d'exploitation de l'hyperviseur, grâce à une optimisation honnête, fournira de moins en moins de temps processeur. Ce processus se produit comme une avalanche et vole des sauts vers le ciel, même si d'autres machines virtuelles peuvent à peine le remarquer. Et plus il y a de cœurs, plus la machine affectée est mauvaise. En bref, ce sont les machines virtuelles très chargées et dotées de nombreux cœurs qui en souffrent le plus.

Low LA, mais il y a du vol. Si LA est d'environ 0,7 (c'est-à-dire que l'hyperviseur semble sous-chargé), mais qu'un vol est observé à l'intérieur de machines virtuelles individuelles :

  • L'option avec paravirtualisation déjà décrite ci-dessus. La machine virtuelle peut recevoir des métriques indiquant un vol, même si l'hyperviseur fonctionne correctement. D'après les résultats de nos expérimentations, cette option 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 calculé. Plus précisément, à chaque instant précis, il est calculé correctement, mais en moyenne sur une minute, il s'avère sous-estimé. Par exemple, si une machine virtuelle sur tiers de l'hyperviseur consomme tous ses processeurs pendant exactement une demi-minute, alors LA par minute sur l'hyperviseur sera de 0,15 ; quatre de ces machines virtuelles fonctionnant simultanément donneront 0,6. Et le fait que pendant une demi-minute sur chacun d'eux il y ait eu un vol sauvage à 25% selon l'indicateur LA ne peut plus être retiré.
  • Encore une fois, à cause du planificateur qui a décidé que quelqu'un mangeait trop et l'a laissé attendre. En attendant, je vais changer de contexte, gérer les interruptions et m'occuper d'autres choses importantes du système. En conséquence, certaines machines virtuelles ne rencontrent aucun problème, tandis que d’autres subissent une grave dégradation des performances.

4. Autres distorsions

Il existe un million d'autres raisons pour fausser le juste retour du temps processeur sur une machine virtuelle. Par exemple, l'hyperthreading et NUMA introduisent des difficultés dans les calculs. Ils confondent complètement le choix du noyau pour exécuter le processus, car le planificateur utilise des coefficients - des poids, ce qui rend le calcul encore plus difficile lors du changement de contexte.

Il existe des distorsions dues à des technologies comme le turbo boost ou à l'inverse le mode économie d'énergie qui, lors du calcul de l'utilisation, peuvent augmenter ou diminuer artificiellement la fréquence voire la tranche horaire sur le serveur. L'activation du turbo boost réduit les performances d'un thread de processeur en raison d'une augmentation des performances d'un autre. À ce stade, les informations sur la fréquence actuelle du processeur ne sont pas transmises à la machine virtuelle et celle-ci pense que quelqu'un lui vole son temps (par exemple, elle a demandé 2 GHz, mais en a reçu la moitié).

En général, les causes de distorsion peuvent être multiples. Vous pouvez trouver autre chose sur un système particulier. Il est préférable de commencer par les livres vers lesquels j'ai donné des liens ci-dessus, et de récupérer les statistiques de l'hyperviseur à l'aide d'utilitaires tels que perf, sysdig, systemtap, dont des dizaines.

5. Conclusions

  1. Un certain nombre de vols peuvent survenir en raison de la paravirtualisation, et cela peut être considéré comme normal. Ils écrivent sur Internet que cette valeur peut être de 5 à 10 %. Cela dépend des applications à l'intérieur de la machine virtuelle et de la charge qu'elle impose à ses périphériques physiques. Ici, il est important de prêter attention à la façon dont les applications se sentent dans les machines virtuelles.
  2. Le rapport entre la charge sur l'hyperviseur et le vol à l'intérieur de la machine virtuelle n'est pas toujours clairement lié ; les deux estimations du vol peuvent être erronées dans des situations spécifiques sous des charges différentes.
  3. Le planificateur a une mauvaise attitude envers les processus qui demandent beaucoup. Il essaie de donner moins à ceux qui demandent plus. Les grandes machines virtuelles sont mauvaises.
  4. Un petit vol peut être la norme même sans paravirtualisation (en tenant compte de la charge à l'intérieur de la machine virtuelle, des caractéristiques de charge des voisins, de la répartition de la charge entre les threads et d'autres facteurs).
  5. Si vous souhaitez découvrir le vol dans un système spécifique, vous devez explorer diverses options, collecter des métriques, les analyser soigneusement et réfléchir à la manière de répartir uniformément la charge. Des écarts par rapport à tous les cas sont possibles, qui doivent être confirmés expérimentalement ou examinés dans le débogueur du noyau.

Source: habr.com

Ajouter un commentaire