
Hallo! Ich möchte in einfachen Worten erklären, wie es zu Steal in virtuellen Maschinen kommt und einige nicht offensichtliche Artefakte vorstellen, die wir bei seiner Untersuchung herausgefunden haben, in die ich als CTO der Cloud-Plattform eintauchen musste. . Die Plattform basiert auf KVM.
CPU-Steal-Zeit ist die Zeit, in der die virtuelle Maschine keine CPU-Ressourcen für ihre Ausführung erhält. Diese Zeit wird nur in Gastbetriebssystemen in Virtualisierungsumgebungen berücksichtigt. Die Gründe, wohin diese bereitgestellten Ressourcen verschwinden, sind, wie im wirklichen Leben, ziemlich nebulös. Aber wir haben uns entschieden, dem auf den Grund zu gehen, und haben eine Reihe von Experimenten durchgeführt. Es wäre nicht korrekt zu sagen, dass wir jetzt alles über Steal wissen, aber wir werden Ihnen einige interessante Erkenntnisse mitteilen.
1. Was ist Steal
Steal ist also eine Metrik, die auf einen Mangel an CPU-Zeit für Prozesse innerhalb der virtuellen Maschine hinweist. Wie beschrieben , steal — dies ist die Zeit, während der der Hypervisor andere Prozesse im Host-Betriebssystem ausführt, während er den Prozess der virtuellen Maschine zur Ausführung anstellt. Das heißt, steal wird als die Differenz zwischen der Zeit betrachtet, zu der der Prozess bereit zur Ausführung ist, und der Zeit, zu der der Prozess Rechenzeit zugewiesen bekommt.
Die Steal-Metrik wird von der virtuellen Maschine vom Hypervisor erhalten. Dabei gibt der Hypervisor nicht an, welche anderen Prozesse er genau ausführt, sondern sagt einfach: „Während ich beschäftigt bin, kann ich dir keine Zeit widmen.“ In KVM wurde die Unterstützung zur Berechnung von steal in hinzugefügt. Es gibt hier zwei Schlüsselpunkte:
- Die virtuelle Maschine erfährt von steal durch den Hypervisor. Das heißt, aus Sicht der Verluste ist dies ein indirektes Maß für die Prozesse auf der virtuellen Maschine, das verschiedenen Verzerrungen unterliegen kann.
- Der Hypervisor teilt der virtuellen Maschine nicht mit, womit er sonst beschäftigt ist — das Hauptanliegen ist, dass er ihr keine Zeit widmet. Daher kann die virtuelle Maschine Verzerrungen im Steal-Wert nicht erkennen, die anhand der Art der konkurrierenden Prozesse bewertet werden könnten.
2. Was beeinflusst steal
2.1. Berechnung von steal
Im Grunde wird Steal ähnlich wie die normale Prozessor-Auslastungszeit betrachtet. Informationen darüber, wie die Auslastung berechnet wird, sind rar. Vermutlich, weil die meisten dieses Thema als offensichtlich erachten. Doch auch hier gibt es Fallstricke. Um mehr über diesen Prozess zu erfahren, können Sie : Sie erfahren viele Details bei der Berechnung der Auslastung und in welchen Situationen diese Berechnung aus den folgenden Gründen fehlerhaft sein kann:
- Überhitzung des Prozessors, bei der Takte übersprungen werden.
- Aktivierung/Deaktivierung des Turbo-Boosts, die zu einer Änderung der Taktrate des Prozessors führt.
- Änderung der Dauer des Zeitquants, die bei der Verwendung von Energiespartechnologien des Prozessors, wie SpeedStep, auftritt.
- Das Problem der durchschnittlichen Berechnung: Eine Auslastung von 80 % über eine Minute kann einen kurzfristigen Burst von 100 % verbergen.
- Die zyklische Sperrung (Spin Lock) führt dazu, dass der Prozessor ausgelastet ist, der Benutzerprozess jedoch keinen Fortschritt bei seiner Ausführung sieht. Infolgedessen wird die berechnete Auslastung des Prozessors durch den Prozess bei hundert Prozent liegen, obwohl physisch keine Prozessorzeit vom Prozess verbraucht wird.
Ich habe keine Artikel gefunden, die eine ähnliche Berechnung für Steal beschreiben (wenn Sie welche kennen – teilen Sie sie bitte in den Kommentaren). Aber judging nach dem Quellcode funktioniert der Berechnungsmechanismus genauso wie bei der Auslastung. Es wird einfach ein weiterer Zähler im Kernel hinzugefügt, der direkt für den KVM-Prozess (Virtuelle Maschine) zuständig ist und die Dauer der Wartezeit des KVM-Prozesses auf Prozessorzeit zählt. Der Zähler entnimmt Informationen vom Prozessor aus dessen Spezifikation und überprüft, ob alle seine Ticks vom virtuellen Prozess genutzt wurden. Wenn ja, gehen wir davon aus, dass der Prozessor nur mit dem virtuellen Prozess beschäftigt war. Andernfalls informieren wir darüber, dass der Prozessor mit etwas anderem beschäftigt war, was Steal ergibt.
Der Prozess zur Berechnung von Steal ist denselben Problemen ausgesetzt wie die herkömmliche Berechnung der Ressourcenauslastung. Diese Probleme treten nicht häufig auf, können jedoch entmutigend erscheinen.
2.2. Arten der Virtualisierung auf KVM
Generell gibt es drei Arten von Virtualisierung, die alle von KVM unterstützt werden. Der Virtualisierungstyp kann den Mechanismus der Entstehung von Steal beeinflussen.
Übertragung. In diesem Fall interagiert das Betriebssystem der virtuellen Maschine mit den physischen Geräten des Hypervisors etwa so:
- Das Gastbetriebssystem sendet einen Befehl an sein Gastgerät.
- Der Treiber des Gastgeräts empfängt den Befehl, formuliert eine Anfrage für das BIOS des Geräts und leitet sie an den Hypervisor weiter.
- Der Prozess des Hypervisors übersetzt den Befehl in einen Befehl für das physische Gerät, wobei er diesen unter anderem sicherer macht.
- Der Treiber des physischen Geräts empfängt den modifizierten Befehl und sendet ihn an das physische Gerät.
- Die Ergebnisse der Befehlsausführung gelangen über denselben Weg zurück.
Der Vorteil der Virtualisierung besteht darin, dass sie die Emulation jedes beliebigen Geräts ermöglicht und keine spezielle Vorbereitung des Betriebssystems erfordert. Allerdings wird dies vor allem auf Kosten der Geschwindigkeit bezahlt.
Hardware-Virtualisierung. In diesem Fall versteht das physische Gerät auf Hardware-Ebene die Befehle des Betriebssystems. Dies ist der schnellste und beste Ansatz. Leider wird er jedoch nicht von allen physischen Geräten, Hypervisoren und Gastbetriebssystemen unterstützt. Derzeit sind die Hauptgeräte, die Hardware-Virtualisierung unterstützen, Prozessoren.
Paravirtualisierung. Die am weitesten verbreitete Form der Virtualisierung von Geräten auf KVM und generell der am meisten genutzte Virtualisierungsmodus für Gastbetriebssysteme. Das Besondere dabei ist, dass die Interaktion mit bestimmten Untersystemen des Hypervisors (zum Beispiel mit dem Netzwerk- oder Speicher-Stack) oder die Zuweisung von Speicherseiten über die API des Hypervisors erfolgt, ohne dass niedrigstufige Befehle übersetzt werden. Ein Nachteil dieser Virtualisierungsart besteht darin, dass der Kernel des Gastbetriebssystems modifiziert werden muss, damit er über diese API mit dem Hypervisor interagieren kann. Dieses Problem wird jedoch in der Regel durch die Installation spezieller Treiber im Gastbetriebssystem gelöst. In KVM wird diese API als .
Bei der Paravirtualisierung wird der Weg zu den physischen Geräten deutlich verkürzt, da Befehle direkt aus der virtuellen Maschine an den Hypervisor-Prozess auf dem Host gesendet werden. Dies beschleunigt die Ausführung aller Anweisungen innerhalb der virtuellen Maschine. In KVM ist hierfür die virtio-API verantwortlich, die nur für bestimmte Geräte wie Netzwerk- oder Festplattentreiber funktioniert. Aus diesem Grund werden in virtuellen Maschinen virtio-Treiber installiert.
Die Kehrseite dieser Beschleunigung ist, dass nicht alle Prozesse, die innerhalb der virtuellen Maschine ausgeführt werden, auch dort bleiben. Dies kann zu bestimmten Effekten führen, die zu 'steal' führen können. Eine eingehende Untersuchung dieses Themas empfehle ich mit .
2.3. 'Fair' Scheduling
Eine virtuelle Maschine auf dem Hypervisor ist faktisch ein herkömmlicher Prozess, der den Gesetzen des Scheduling (Ressourcenzuweisung zwischen Prozessen) im Linux-Kernel unterliegt. Daher werden wir diesen Punkt genauer betrachten.
In Linux wird der sogenannte CFS, der Completely Fair Scheduler, ab Kernel 2.6.23 als Standard-Scheduler verwendet. Um diesen Algorithmus zu verstehen, kann man die Linux Kernel Architektur oder die Quelltexte lesen. Der Grundgedanke von CFS ist die Verteilung der Prozessorzeit auf Prozesse, abhängig von der Dauer ihrer Ausführung. Je mehr Prozessorzeit ein Prozess benötigt, desto weniger erhält er. Dies gewährleistet eine "faire" Ausführung aller Prozesse – sodass kein einzelner Prozess ständig alle Prozessoren beansprucht und auch andere Prozesse ausgeführt werden können.
Manchmal führt dieses Paradigma zu interessanten Artefakten. Langjährige Linux-Nutzer erinnern sich sicherlich an das Einfrieren des üblichen Texteditors auf dem Desktop beim Start ressourcenintensiver Anwendungen wie eines Compilers. Dies geschah, weil ressourcenleichte Aufgaben von Desktop-Anwendungen mit ressourcenintensiven Aufgaben wie dem Compiler konkurrierten. CFS betrachtet dies als unfair und stoppt daher regelmäßig den Texteditor, um dem Prozessor die Verarbeitung der Compiler-Aufgaben zu ermöglichen. Dies wurde mit Hilfe eines Mechanismus behoben. , aber es gibt viele weitere Aspekte bei der Verteilung der Prozessorzeit zwischen den Aufgaben. Tatsächlich geht es nicht darum, wie schlecht es im CFS ist, sondern vielmehr darum, darauf hinzuweisen, dass eine "faire" Verteilung der Prozessorzeit keine triviale Aufgabe ist.
Ein weiterer wichtiger Punkt im Scheduler ist die Preemption. Dies ist notwendig, um einen übermäßig ressourcenintensiven Prozess von der CPU zu verdrängen und anderen Prozessen die Möglichkeit zu geben, zu arbeiten. Der Vorgang des Verdrängens wird als Kontextwechsel bezeichnet. Dabei wird der gesamte Kontext der Aufgabe gespeichert: Stack-Zustand, Register und weitere Informationen, wonach der Prozess in den Wartezustand versetzt wird und ein anderer Prozess seine Stelle einnimmt. Dies ist eine aufwendige Operation für das Betriebssystem und wird selten durchgeführt, aber prinzipiell ist daran nichts Schlechtes. Häufige Kontextwechsel können auf ein Problem im Betriebssystem hindeuten, aber normalerweise erfolgt dies kontinuierlich und weist auf nichts besonders hin.
Die lange Erklärung dient dazu, einen Fakt zu verdeutlichen: Je mehr CPU-Ressourcen ein Prozess in einem fairen Linux-Scheduler zu verbrauchen versucht, desto schneller wird er gestoppt, damit auch andere Prozesse aktiv werden können. Ob das richtig ist oder nicht, ist eine komplexe Frage, die unter verschiedenen Lasten unterschiedlich gelöst wird. In Windows war der Scheduler bis vor kurzem darauf ausgelegt, Desktop-Anwendungen priorisiert zu verarbeiten, weshalb Hintergrundprozesse manchmal ausgebremst wurden. In Sun Solaris gab es fünf verschiedene Klassen von Scheduler. Mit der Einführung der Virtualisierung wurde ein sechster hinzugefügt, , da die vorherigen fünf mit der Virtualisierung von Solaris Zones nicht richtig funktionierten. Eine detaillierte Auseinandersetzung mit diesem Thema empfehle ich, beginnend mit Büchern wie oder .
2.4. Wie überwacht man den Steal?
Den Steal innerhalb einer virtuellen Maschine zu überwachen, ist wie bei jeder anderen CPU-Metrik einfach: Sie können jedes beliebige Tool zur Erfassung von CPU-Metriken verwenden. Wichtig ist, dass die virtuelle Maschine auf Linux läuft. Windows hingegen stellt diese Art von Informationen seinen Benutzern aus irgendeinem Grund nicht zur Verfügung. 🙁

Ausgabe des top-Befehls: Detailierte CPU-Auslastung in der ganz rechten Spalte — steal
Die Herausforderungen entstehen bei dem Versuch, diese Informationen vom Hypervisor zu erhalten. Man kann versuchen, den Steal-Wert auf der Hostmaschine zu prognostizieren, zum Beispiel durch den Load Average (LA) — den Durchschnittswert der Prozesse, die auf ihre Ausführung warten. Die Berechnung dieses Parameters ist kompliziert, aber ganz allgemein gilt: Wenn der normierte LA im Verhältnis zur Anzahl der CPU-Threads größer als 1 ist, bedeutet das, dass der Linux-Server überlastet ist.
Worauf warten all diese Prozesse? Die offensichtliche Antwort ist — auf die CPU. Doch diese Antwort ist nicht ganz korrekt, denn manchmal ist die CPU frei, während der LA hoch ist. Denken Sie daran, . Ähnlich kann es mit der Festplatte und anderen Ein- und Ausgabe-Geräten sein. Tatsächlich können Prozesse auf das Ende jeder Art von Blockierung warten, sei es eine physische Blockierung, die mit dem Ein- und Ausgabe-Gerät zusammenhängt, oder eine logische Blockierung, wie zum Beispiel bei Mutexen. Dazu gehören auch Hardware-Blockierungen (wie die gleiche Antwort von der Festplatte) oder logische Blockierungen (sogenannte Blockierungsprimitive, zu denen viele Entitäten gehören, wie adaptive und Spin-Mutexe, Semaphore, Bedingungsvariablen, rw Locks, ipc Locks…
Ein weiteres Merkmal der LA ist, dass sie als Durchschnittswert des Betriebssystems betrachtet wird. Zum Beispiel konkurrieren 100 Prozesse um eine Datei, und dann ist LA=50. Ein so hoher Wert scheint darauf hinzudeuten, dass das Betriebssystem schlecht funktioniert. Aber für einen anderen schlecht geschriebenen Code kann dies ein normales Verhalten darstellen, bei dem nur dieser spezifische Code leidet, während andere Prozesse im Betriebssystem nicht betroffen sind.
Aufgrund dieser Durchschnittsbildung (die mindestens eine Minute dauert) ist es im Allgemeinen kein einfaches Unterfangen, etwas anhand des LA-Wertes zu bestimmen, da die Ergebnisse in spezifischen Fällen sehr ungewiss sind. Wenn Sie versuchen, es zu verstehen, werden Sie feststellen, dass in Artikeln auf Wikipedia und anderen verfügbaren Ressourcen nur die einfachsten Fälle beschrieben werden, ohne eine tiefgehende Erklärung des Prozesses. Alle, die interessiert sind, verweise ich erneut — weiter über die Links. Wer keine Lust auf Englisch hat — .
3. Effekte
Jetzt gehen wir auf die Hauptfälle des Auftretens von Steal ein, mit denen wir konfrontiert wurden. Ich werde erläutern, wie sie aus dem oben Gesagten hervorgehen und wie sie mit den Werten auf dem Hypervisor in Beziehung stehen.
Reutilisierung. Das Einfachste und häufigste: Der Hypervisor wird überlastet. Tatsächlich laufen viele virtuelle Maschinen, die CPU-Nutzung ist hoch und es gibt viel Konkurrenz, die Auslastung pro LA liegt über 1 (normiert nach CPU-Threads). Innerhalb aller virtuellen Maschinen läuft alles langsam. Der Steal, der vom Hypervisor übertragen wird, steigt ebenfalls an; es muss eine Lastverteilung erfolgen oder jemand muss abgeschaltet werden. Alles ist schlüssig und nachvollziehbar.
Paravirtualisierung gegen isolierte Instanzen. Auf dem Hypervisor befindet sich lediglich eine virtuelle Maschine, die nur einen kleinen Teil seiner Kapazität benötigt, aber eine hohe Last in Bezug auf Ein-/Ausgabe, beispielsweise auf der Festplatte, erzeugt. Und irgendwo in ihr tritt ein minimaler Steal auf, bis zu 10 % (wie mehrere durchgeführte Experimente zeigen).
Das ist ein interessantes Phänomen. Das Stehlen von Zeit tritt hier auf, weil es durch Blockierungen auf der Ebene der paravirtualisierten Treiber verursacht wird. Innerhalb der virtuellen Maschine wird eine Unterbrechung erzeugt, die vom Treiber verarbeitet und an den Hypervisor weitergeleitet wird. Aufgrund der Verarbeitung der Unterbrechung sieht die virtuelle Maschine dies als einen gesendeten Antrag an, sie ist bereit zur Ausführung und wartet auf den Prozessor, aber ihr wird keine Prozessorzeit zugewiesen. Die virtuelle Maschine denkt, dass diese Zeit gestohlen wurde.
Dies geschieht im Moment des Sendens des Puffers, der in den Kernel-Space des Hypervisors übertragen wird, und wir beginnen, darauf zu warten. Aus der Sicht der virtuellen Maschine sollte dieser jedoch sofort zurückkommen. Folglich wird laut dem Steal-Berechnungsalgorithmus diese Zeit als gestohlen betrachtet. In dieser Situation könnten wahrscheinlich auch andere Mechanismen vorhanden sein (zum Beispiel die Verarbeitung anderer Systemaufrufe), aber diese sollten sich nicht stark unterscheiden.
Der Scheduler gegen stark belastete virtuelle Maschinen. Wenn eine virtuelle Maschine stärker von Steal betroffen ist als andere, liegt das am Scheduler. Je höher die Auslastung des Prozessors durch einen Prozess ist, desto eher wird der Scheduler diesen Prozess abbrechen, damit andere ebenfalls arbeiten können. Wenn eine virtuelle Maschine wenig Ressourcen benötigt, sieht sie fast keinen Steal: Ihr Prozess wartet brav und sollte mehr Zeit bekommen. Wenn eine virtuelle Maschine jedoch alle ihre Kerne maximal auslastet, wird sie häufiger vom Prozessor abgedrängt und erhält weniger Zeit.
Es wird noch schlimmer, wenn Prozesse innerhalb der virtuellen Maschine versuchen, mehr Prozessorleistung zu beanspruchen, weil sie mit der Datenverarbeitung nicht zurechtkommen. In diesem Fall wird das Betriebssystem auf dem Hypervisor, durch faire Optimierung, immer weniger Prozessorzeit zuweisen. Dieser Prozess geschieht lawinenartig und der Steal-Wert schießt in die Höhe, während andere virtuelle Maschinen ihn kaum bemerken. Je mehr Kerne, desto schlechter ergeht es der betroffenen Maschine. Kurz gesagt, stark beanspruchte virtuelle Maschinen mit vielen Kernen leiden am meisten.
Niedriger LA, aber es gibt Steal. Wenn der LA etwa 0,7 beträgt (d.h. der Hypervisor scheint unterlastet zu sein), es jedoch innerhalb der einzelnen VMs zu Steal kommt:
- Dies ist die bereits oben beschriebene Methode der Paravirtualisierung. Die virtuelle Maschine kann Metriken erhalten, die auf Steal hinweisen, während beim Hypervisor alles in Ordnung ist. Laut unseren Experimenten überschreitet dieser Steal nicht 10 % und sollte keine wesentlichen Auswirkungen auf die Leistung der Anwendungen innerhalb der virtuellen Maschine haben.
- Der LA-Wert wird fälschlicherweise berechnet. Genauer gesagt, wird er in jedem einzelnen Moment korrekt berechnet, aber bei der Durchschnittsbildung über eine Minute wird er zu niedrig angegeben. Wenn beispielsweise eine VM ein Drittel der Ressourcen des Hypervisors für genau eine halbe Minute nutzt, beträgt der LA-Wert für die Minute am Hypervisor 0,15; vier solcher VMs, die gleichzeitig laufen, ergeben 0,6. Und dass es für eine halbe Minute auf jeder von ihnen einen massiven Steal von etwa 25 % beim LA-Wert gab, ist danach nicht mehr nachvollziehbar.
- Wegen desSchedulers entscheidet, dass jemand zu viel frisst und dieser jemand warten muss. In der Zwischenzeit wechsle ich den Kontext, bearbeite Unterbrechungen und kümmere mich um andere wichtige Systemaufgaben. Letztendlich haben einige virtuelle Maschinen keine Probleme, während andere ernsthafte Leistungsdegradation erleben.
4. Weitere Verzerrungen
Es gibt noch viele andere Gründe für Verzerrungen bei der gerechten Verteilung der CPU-Zeit auf virtuellen Maschinen. Beispielsweise tragen Hyper-Threading und NUMA zur Komplexität der Berechnungen bei. Sie verwirren die Auswahl des Kerns für die Ausführung des Prozesses endgültig, da der Scheduler Koeffizienten – Gewichte – verwendet, die das Timing bei Context-Switches noch komplizierter machen.
Es kann Verzerrungen aufgrund von Technologien wie Turbo-Boost oder im Gegenteil, Energiesparmodi geben, die bei der Berechnung der Auslastung die Frequenz oder sogar die Zeitquantum auf dem Server künstlich erhöhen oder senken können. Das Aktivieren des Turbo-Boosts verringert die Leistung eines Prozessor-Threads aufgrund der erhöhten Leistung eines anderen. Zu diesem Zeitpunkt werden der virtuellen Maschine keine Informationen über die aktuelle Prozessorfrequenz übermittelt, was dazu führt, dass sie denkt, ihre Zeit werde von jemandem entwendet (zum Beispiel hat sie 2 GHz angefordert, aber erhält die Hälfte).
Insgesamt kann es viele Gründe für Verzerrungen geben. In einem bestimmten System könnten Sie noch etwas anderes feststellen. Am besten beginnen Sie mit den Büchern, für die ich oben Links bereitgestellt habe, und der Erfassung von Statistiken vom Hypervisor mit Tools wie perf, sysdig, systemtap, von denen es .
5. Fazit
- Ein gewisser Steal kann durch Paravirtualisierung entstehen und wird als normal angesehen. Im Internet liest man, dass dieser Wert 5-10 % betragen kann. Dies hängt von den Anwendungen innerhalb der virtuellen Maschine und der Belastung der physischen Geräte ab. Es ist wichtig, darauf zu achten, wie sich die Anwendungen innerhalb der virtuellen Maschinen verhalten.
- Das Verhältnis von Belastung im Hypervisor und Steal innerhalb der virtuellen Maschine ist nicht immer eindeutig miteinander verknüpft; beide Steal-Bewertungen können in bestimmten Situationen bei unterschiedlichen Lasten fehlerhaft sein.
- Der Scheduler hat eine negative Haltung gegenüber Prozessen, die viel anfordern. Er versucht, weniger Ressourcen denen zuzuweisen, die mehr verlangen. Große virtuelle Maschinen sind problematisch.
- Ein gewisser Steal kann auch ohne Paravirtualisierung normal sein (unter Berücksichtigung der Last innerhalb der virtuellen Maschine, der Besonderheiten der Nachbarlasten, der Verteilung der Last auf Threads und anderer Faktoren).
- Wenn Sie herausfinden möchten, was Steal in einem bestimmten System bedeutet, müssen Sie verschiedene Optionen untersuchen, Metriken sammeln, diese sorgfältig analysieren und überlegen, wie die Last gleichmäßig verteilt werden kann. Abweichungen von den verschiedenen Fällen müssen experimentell bestätigt oder im Kern-Debugger betrachtet werden.
Quelle: habr.com
