
Hallo! Ich möchte in einfacher Sprache über die Mechanik des CPU-Steals innerhalb von virtuellen Maschinen und einige weniger offensichtliche Artefakte sprechen, die wir bei unserer Untersuchung herausgefunden haben, in die ich als technischer Direktor der Cloud-Plattform eintauchen musste. . Die Plattform läuft auf KVM.
Die CPU-Steal-Zeit ist die Zeit, in der eine virtuelle Maschine keine CPU-Ressourcen für ihre Ausführung erhält. Diese Zeit wird nur in den Gast-Betriebssystemen in Virtualisierungsumgebungen erfasst. Die Gründe dafür, wohin diese zugewiesenen Ressourcen verschwinden, sind, wie im echten Leben, recht vage. Aber wir haben beschlossen, das herauszufinden und eine Reihe von Experimenten durchzuführen. Es ist nicht so, dass wir jetzt alles über Steal wissen, aber wir werden dir etwas Interessantes erzählen.
1. Was ist Steal
Also, Steal ist eine Kennzahl, die auf den Mangel an CPU-Zeit für Prozesse innerhalb der virtuellen Maschine hinweist. Wie beschrieben , ist Steal die Zeit, während der der Hypervisor andere Prozesse auf dem Host-Betriebssystem ausführt, obwohl er den Prozess der virtuellen Maschine zum Ausführen in die Warteschlange gestellt hat. Das heißt, Steal wird als die Differenz zwischen der Zeit, in der der Prozess bereit zur Ausführung ist, und der Zeit, zu der dem Prozess CPU-Zeit zugewiesen wird, betrachtet.
Die Steal-Kennzahl erhält die virtuelle Maschine vom Hypervisor. Der Hypervisor gibt dabei jedoch nicht an, welche anderen Prozesse er ausführt; er sagt einfach: „Ich kann dir keine Zeit widmen, da ich beschäftigt bin“. Auf KVM wurde die Unterstützung zur Berechnung von Steal in . Hier gibt es zwei entscheidende Punkte:
- Die virtuelle Maschine erfährt von Steal durch den Hypervisor. Das heißt, aus Sicht der Verluste ist es für die Prozesse in der virtuellen Maschine eine indirekte Messung, die verschiedenen Verzerrungen unterliegen kann.
- Der Hypervisor teilt der virtuellen Maschine keine Informationen darüber mit, womit er sonst beschäftigt ist – das Hauptsache ist, dass er ihr keine Zeit widmet. Dadurch kann die virtuelle Maschine selbst keine Verzerrungen in der Steal-Kennzahl feststellen, die man anhand der Art der konkurrierenden Prozesse bewerten könnte.
2. Was beeinflusst Steal
2.1. Berechnung von Steal
Im Grunde genommen wird Steal auf ähnliche Weise berechnet wie die gewöhnliche Auslastungszeit der CPU. Es gibt nicht viele Informationen darüber, wie die Auslastung berechnet wird. Wahrscheinlich, weil die meisten diesen Aspekt für selbstverständlich halten. Aber auch hier gibt es Tücken. Um sich mit diesem Prozess vertraut zu machen, kann man lesen : Sie erfahren eine Menge Details zur Berechnung der Auslastung und zu Situationen, in denen diese Berechnung aus folgenden Gründen fehlerhaft sein kann:
- Überhitzung des Prozessors, bei der Taktzyklen ausgelassen werden.
- Aktivierung/Deaktivierung des Turbo-Boosts, wodurch sich die Taktfrequenz des Prozessors ändert.
- Änderung der Zeitquantum-Dauer, die bei Verwendung von Energiespartechnologien des Prozessors auftritt, zum Beispiel SpeedStep.
- Das Problem bei der Durchschnittsberechnung: Eine Auslastung von 80 % über eine Minute kann einen kurzen Burst von 100 % verbergen.
- Eine zyklische Sperre (spin lock) führt dazu, dass der Prozessor ausgelastet ist, der Benutzerprozess jedoch keine Fortschritte bei seiner Ausführung sieht. Infolgedessen wird die berechnete Auslastung des Prozessors durch den Prozess 100 % betragen, obwohl die physische Prozessorzeit vom Prozess nicht verbraucht wird.
Ich habe keinen Artikel gefunden, der eine ähnliche Berechnung für steal beschreibt (wenn Sie einen kennen, teilen Sie ihn bitte in den Kommentaren). Aber laut den Quellcodes ist der Berechnungsmechanismus derselbe wie für die Auslastung. Im Kern wird lediglich ein zusätzlicher Zähler hinzugefügt, der direkt für den KVM-Prozess (Virtuelle Maschine) verantwortlich ist und die Dauer der Wartezeit des KVM-Prozesses auf die Prozessorzeit zählt. Der Zähler bezieht seine Informationen über den Prozessor aus dessen Spezifikation und prüft, ob alle seine Taktzyklen vom Virtuellen Prozess genutzt wurden. Falls ja, gehen wir davon aus, dass der Prozessor nur mit dem virtuellen Maschinenprozess beschäftigt war. Andernfalls informieren wir darüber, dass der Prozessor auch mit etwas anderem beschäftigt war, es trat steal auf.
Der Prozess zur Berechnung von steal ist denselben Problemen wie die gewöhnliche Auslastungsberechnung ausgesetzt. Man kann nicht sagen, dass solche Probleme häufig auftreten, aber sie sehen entmutigend aus.
2.2. Arten der Virtualisierung unter KVM
Generell gibt es drei Arten der Virtualisierung, die alle von KVM unterstützt werden. Die Art der Virtualisierung kann den Mechanismus für das Entstehen von steal beeinflussen.
Übertragung. In diesem Fall erfolgt die Interaktion des Betriebssystems der virtuellen Maschine mit den physikalischen Geräten des Hypervisors ungefähr so:
- Das Gastbetriebssystem sendet einen Befehl an sein Gastgerät.
- Der Treiber des Gastgeräts empfängt den Befehl, erstellt eine Anfrage für das BIOS des Geräts und sendet sie an den Hypervisor.
- Der Hypervisor-Prozess übersetzt den Befehl in einen Befehl für das physische Gerät und macht ihn dadurch unter anderem sicherer.
- Der Treiber des physischen Geräts nimmt den modifizierten Befehl entgegen und sendet ihn an das physische Gerät.
- Die Ergebnisse der Befehlsausführung gehen denselben Weg zurück.
Der Vorteil der Übersetzung besteht darin, dass sie ermöglicht, jedes Gerät zu emulieren und keine spezielle Vorbereitung des Betriebssystemkerns erfordert. Dafür muss man jedoch vor allem auf die Geschwindigkeit verzichten.
Hardware-Virtualisierung. In diesem Fall versteht das Gerät auf physischer Ebene die Befehle des Betriebssystems. Dies ist der schnellste und beste Weg. 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 (paravirtualization). Die am weitesten verbreitete Art der Gerätevigilisierung auf KVM und überhaupt der am weitesten verbreitete Virtualisierungsmodus für Gastbetriebssysteme. Sein Merkmal ist, dass die Arbeit mit bestimmten Hypervisor-Subsystemen (zum Beispiel mit dem Netzwerk- oder Festplattentreiber) oder die Zuweisung von Speicherseiten unter Verwendung der Hypervisor-API erfolgt, ohne dass niedrigstufige Befehle übersetzt werden. Ein Nachteil dieser Virtualisierungsart ist die Notwendigkeit, den Kern des Gastbetriebssystems zu modifizieren, damit er über diese API mit dem Hypervisor interagieren kann. Dies wird jedoch in der Regel durch die Installation spezieller Treiber im Gastbetriebssystem gelöst. In KVM wird diese API genannt .
Bei der Paravirtualisierung im Vergleich zur Übersetzung wird der Weg zum physischen Gerät erheblich verkürzt, indem die 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 dafür die virtio API verantwortlich, die nur für bestimmte Geräte wie Netzwerk- oder Festplattentreiber funktioniert. Aus diesem Grund werden in die virtuellen Maschinen virtio-Treiber installiert.
Die Kehrseite einer solchen Beschleunigung ist, dass nicht alle Prozesse, die innerhalb der virtuellen Maschine ausgeführt werden, dort verbleiben. Dies erzeugt spezielle Effekte, die zu einem Auftreten bei steal führen können. Eine detaillierte Untersuchung dieses Themas empfehle ich, zu beginnen mit .
2.3. „Gerechte“ Planung
Eine virtuelle Maschine auf einem Hypervisor ist tatsächlich ein gewöhnlicher Prozess, der den Regeln der Planung (Ressourcenverteilung zwischen Prozessen) im Linux-Kernel unterliegt, daher betrachten wir ihn näher.
In Linux wird der sogenannte CFS, Completely Fair Scheduler, seit Kernel 2.6.23 als Standard-Dispatcher verwendet. Um diesen Algorithmus zu verstehen, kann man die Linux Kernel Architecture oder den Source Code lesen. Die Essenz des CFS besteht darin, die CPU-Zeit zwischen Prozessen in Abhängigkeit von der Dauer ihrer Ausführung zu verteilen. Je mehr CPU-Zeit ein Prozess benötigt, desto weniger Zeit erhält er. Dies garantiert eine „gerechte“ Ausführung aller Prozesse — damit ein Prozess nicht ständig alle Prozessoren belegt und auch andere Prozesse ausgeführt werden können.
Manchmal führt ein solches Paradigma zu interessanten Artefakten. Langjährige Linux-Nutzer erinnern sich sicherlich an das Einfrieren von normalen Texteditoren auf dem Desktop während des Starts ressourcenintensiver Anwendungen wie Compiler. Dies geschah, weil ressourcenunintensive Aufgaben von Desktop-Anwendungen mit ressourcenintensiven Aufgaben wie dem Compiler konkurrierten. CFS hält dies für unfair, weshalb es den Texteditor periodisch stoppt und der CPU ermöglicht, die Aufgaben des Compilers zu bearbeiten. Dies wurde durch einen Mechanismus korrigiert , aber es blieben viele andere Besonderheiten bei der Verteilung der CPU-Zeit zwischen Aufgaben. Tatsächlich handelt es sich hierbei nicht um einen Bericht darüber, wie schlecht alles beim CFS ist, sondern um den Versuch, auf die Tatsache aufmerksam zu machen, dass die „gerechte“ Verteilung der CPU-Zeit keine triviale Aufgabe ist.
Ein weiterer wichtiger Punkt im Scheduler ist die Preemption. Dies ist notwendig, um einen überlasteten Prozess vom Prozessor zu entfernen und anderen Prozessen die Möglichkeit zu geben, zu arbeiten. Der Prozess des Entfernens wird als Kontextwechsel bezeichnet, wobei der Kontext des Tasks wie der Stack-Zustand, Register und anderes erhalten bleibt, bevor der Prozess zum Warten geschickt wird und ein anderer an seine Stelle tritt. Dies ist eine kostspielige Operation für das Betriebssystem und wird selten verwendet, aber grundsätzlich ist daran nichts Schlechtes. Häufige Kontextwechsel können auf ein Problem im Betriebssystem hinweisen, aber normalerweise verlaufen sie kontinuierlich und deuten auf nichts Besonderes hin.
Diese ausführliche Erklärung ist nötig, um einen Fakt zu verdeutlichen: Je mehr Ressourcen der Prozessor von einem Prozess in einem fairen Scheduler von Linux zu beanspruchen versucht, desto schneller wird dieser gestoppt, damit auch andere Prozesse arbeiten können. Ob dies richtig oder falsch ist, ist eine komplexe Frage, die unter verschiedenen Lasten unterschiedlich beantwortet wird. Bis vor kurzem war der Scheduler in Windows auf die priorisierte Verarbeitung von Desktop-Anwendungen ausgerichtet, wodurch Hintergrundprozesse zum Einfrieren neigten. In Sun Solaris gab es fünf verschiedene Klassen von Schedulern. Als die Virtualisierung eingeführt wurde, wurde die sechste hinzugefügt, , weil die vorherigen fünf mit der Virtualisierung der Solaris Zones unangemessen arbeiteten. Eine detaillierte Untersuchung dieses Themas empfehle ich Ihnen, mit Büchern wie oder .
2.4. Wie kann man Steal überwachen?
Steal innerhalb einer virtuellen Maschine zu überwachen, ist wie jede andere prozessorgestützte Metrik einfach: Sie können jedes Metrik-Sammeltool für Prozessoren verwenden. Das Wichtigste ist, dass die virtuelle Maschine unter Linux läuft. Windows stellt aus irgendeinem Grund diese Informationen seinen Benutzern nicht zur Verfügung. 🙁

Ausgabe des Befehls top: Detaillierung der Prozessorlast, in der äußersten rechten Spalte — Steal
Die Schwierigkeit tritt auf, wenn man versucht, diese Informationen vom Hypervisor zu erhalten. Man kann versuchen, den Steal auf der Hostmaschine zu prognostizieren, beispielsweise anhand des Parameters Load Average (LA) — eines durchschnittlichen Wertes der Anzahl von Prozessen, die in der Warteschlange auf die Ausführung warten. Die Berechnungsmethode dieses Parameters ist nicht einfach, aber im Allgemeinen, wenn der auf die Anzahl der Prozessor-Threads normierte LA größer als 1 ist, deutet dies darauf hin, dass der Server mit Linux aus irgendeinem Grund überlastet ist.
Was erwarten all diese Prozesse? Die offensichtliche Antwort ist der Prozessor. Aber die Antwort ist nicht ganz korrekt, denn manchmal ist der Prozessor frei, während die LA übersteigt. Denken Sie daran, Ähnliches kann auch bei Festplatten und anderen Eingabe-/Ausgabegeräten vorkommen. Aber tatsächlich können Prozesse auf das Ende jeglicher Blockierungen warten, sowohl physischer Art, die mit Eingabe-/Ausgabegeräten verbunden sind, als auch logischer Art, wie z. B. Mutexes. Dazu zählen auch Hardware-Blockierungen (die gleiche Antwort von der Festplatte) oder logische Blockierungen (die sogenannten Sperrprimitive, zu denen viele Entitäten gehören, wie adaptive Mutexes und Spinlocks, Semaphore, Bedingungsvariablen, rw Locks, ipc Locks…).
Ein weiteres Merkmal von LA ist, dass es als Durchschnittswert im Betriebssystem betrachtet wird. Zum Beispiel, wenn 100 Prozesse um eine Datei konkurrieren, dann ist LA=50. So ein hoher Wert könnte darauf hindeuten, dass das Betriebssystem Schwierigkeiten hat. Aber für gewissermaßen schlecht geschriebene Codes kann das ein normales Zustand sein, wobei nur dieser Prozess betroffen ist und andere Prozesse im Betriebssystem nicht leiden.
Wegen dieser Mittelwertbildung (in der Regel über mindestens eine Minute) ist es nicht gerade einfach, irgendetwas anhand der LA-Messung zu bestimmen — die Ergebnisse in bestimmten Fällen sind eher unklar. Wenn Sie versuchen, das herauszufinden, werden Sie feststellen, dass in Wikipedia-Artikeln und anderen verfügbaren Ressourcen nur die einfachsten Fälle beschrieben werden, ohne tiefere Erklärungen des Prozesses. Alle Interessierten verweise ich daher erneut — weiter über die Links. Wer sich auf Englisch nicht wohlfühlt — .
3. Spezialeffekte
Jetzt wollen wir uns mit den Hauptfällen von Steal befassen, die wir erlebt haben. Ich werde erklären, wie sie aus dem oben Gesagten hervorgehen und wie sie sich auf die Metriken im Hypervisor beziehen.
Re-Utilisierung. Das Einfachste und Häufigste: Der Hypervisor ist überlastet. Tatsächlich gibt es viele gestartete virtuelle Maschinen, einen hohen CPU-Verbrauch innerhalb dieser, große Konkurrenz, eine LA-Utilisierung von über 1 (normiert auf die Prozessorthreads). Innerhalb der virtuellen Maschinen läuft alles langsam. Der Steal, der vom Hypervisor übertragen wird, steigt ebenfalls an, und es ist notwendig, die Last neu zu verteilen oder jemanden auszuschalten. Insgesamt ist das alles logisch und verständlich.
Paravirtualisierung vs. einzelne Instanzen. Auf dem Hypervisor gibt es eine einzige virtuelle Maschine, die einen kleinen Teil davon konsumiert, aber eine hohe Last beim Ein- und Ausgeben erzeugt, zum Beispiel beim Speicher. Und irgendwo in ihr erscheint ein kleiner Steal, bis zu 10 % (wie mehrere durchgeführte Experimente zeigen).
Ein interessanter Fall. Der Steal entsteht hier gerade wegen der Sperren auf der Ebene der paravirtualisierten Treiber. Innerhalb der virtuellen Maschine entsteht eine Unterbrechung, die vom Treiber verarbeitet wird und zum Hypervisor geht. Wegen der Unterbrechungsverarbeitung auf dem Hypervisor sieht es für die virtuelle Maschine so aus, als wäre eine Anfrage gesendet worden; sie ist bereit zur Ausführung und wartet auf die CPU, aber ihr wird keine Prozessorzeit gegeben. Die virtuelle Maschine denkt, diese Zeit sei gestohlen.
Dies geschieht im Moment des Sendens eines Puffers, der in den Kernel-Space des Hypervisors geht, und wir beginnen darauf zu warten. Obwohl aus der Sicht der virtuellen Maschine dieser sofort zurückkommen sollte. Folglich wird laut dem Algorithmus zur Berechnung des Steals diese Zeit als gestohlen angesehen. Wahrscheinlich gibt es in dieser Situation auch andere Mechanismen (zum Beispiel die Verarbeitung anderer Systemaufrufe), aber sie sollten sich nicht stark unterscheiden.
Scheduler gegen stark belastete virtuelle Maschinen. Wenn eine virtuelle Maschine mehr unter Steal leidet als andere, hängt das genau mit dem Scheduler zusammen. Je stärker ein Prozess die CPU belastet, desto schneller wird ihn der Scheduler herauswerfen, damit auch die anderen arbeiten können. Wenn die virtuelle Maschine wenig konsumiert, wird sie Steal kaum bemerken: Ihr Prozess hat brav gesessen und gewartet, ihm sollte mehr Zeit gegeben werden. Wenn die virtuelle Maschine die maximale Last über alle ihre Kerne erzeugt, wird sie häufiger von der CPU geworfen und es wird versucht, ihr nicht viel Zeit zu geben.
Es ist noch schlimmer, wenn Prozesse innerhalb der virtuellen Maschine versuchen, mehr CPU zu gewinnen, weil sie mit der Verarbeitung der Daten nicht zurechtkommen. Dann wird das Betriebssystem auf dem Hypervisor, durch ehrliche Optimierung, immer weniger Prozessorzeit gewähren. Dieser Prozess geschieht lawinenartig, und der Steal schnellt in die Höhe, während die anderen virtuellen Maschinen kaum etwas bemerken. Und je mehr Kerne, desto schlechter für die betroffene Maschine. Kurz gesagt, stark belastete virtuelle Maschinen mit vielen Kernen leiden am meisten.
Niedriger LA, aber es gibt Steal. Wenn der LA etwa 0,7 beträgt (das heißt, der Hypervisor erscheint unterlastet), aber innerhalb einzelner virtueller Maschinen Steal beobachtet wird:
- Die bereits oben beschriebene Variante mit Paravirtualisierung. Die virtuelle Maschine kann Metriken erhalten, die auf Steals hinweisen, obwohl beim Hypervisor alles gut ist. Nach den Ergebnissen unserer Experimente übersteigt ein solches Steal 10 % nicht und sollte keinen wesentlichen Einfluss auf die Leistung von Anwendungen innerhalb der virtuellen Maschine haben.
- Der Parameter LA wird falsch angesehen. Genauer gesagt, er wird zu jedem bestimmten Zeitpunkt korrekt betrachtet, aber bei der Durchschnittsbildung über eine Minute wird er zu niedrig ausgewiesen. Wenn beispielsweise eine virtuelle Maschine ein Drittel des Hypervisors genau eine halbe Minute lang alle ihre Prozessoren beansprucht, beträgt der LA für eine Minute beim Hypervisor 0,15; vier solcher virtuellen Maschinen, die gleichzeitig arbeiten, ergeben 0,6. Dass während dieser halben Minute bei jeder von ihnen ein drastischer Steal von 25 % im LA-Wert war, lässt sich nicht mehr herausholen.
- Wieder einmal aufgrund desSchedulers, der entschieden hat, dass jemand zu viel frisst, und dieser jemand warten soll. Während ich das Kontext wechsle, Unterbrechungen bearbeite und mich um andere wichtige Systemangelegenheiten kümmere. Letztendlich sehen einige virtuelle Maschinen keine Probleme, während andere unter schwerer Leistungseinbuße leiden.
4. Andere Verzerrungen
Es gibt noch Millionen von Gründen für Verzerrungen in der fairen Zuteilung der Prozessorzeit in der virtuellen Maschine. Zum Beispiel führen Hyper-Threading und NUMA zu Schwierigkeiten bei den Berechnungen. Sie verwirren die Auswahl des Kerns für die Ausführung eines Prozesses, da der Scheduler Gewichte verwendet, die die Berechnungen bei Kontextwechseln noch komplexer machen.
Es können Verzerrungen durch Technologien wie Turbo-Boost oder umgekehrt durch Energiesparmodi auftreten, die bei der Berechnung der Auslastung künstlich die Frequenz oder sogar das Zeitquantum auf dem Server erhöhen oder senken können. Das Aktivieren von Turbo-Boost verringert die Leistung eines Prozessor-Threads aufgrund der erhöhten Leistung eines anderen. In diesem Moment wird der virtuellen Maschine keine aktuelle Frequenz des Prozessors übermittelt, und sie glaubt, dass ihre Zeit gestohlen wird (zum Beispiel, sie hat 2 GHz angefordert, erhält aber nur die Hälfte).
Insgesamt kann es viele Gründe für Verzerrungen geben. In einem bestimmten System können Sie noch etwas anderes entdecken. Beginnen Sie am besten mit den Büchern, auf die ich oben verwiesen habe, und der Erfassung von Statistiken vom Hypervisor mit Tools wie perf, sysdig, systemtap, von denen es .
5. Fazit
- Eine gewisse Menge an Steal kann durch Paravirtualisierung entstehen und gilt als normal. Im Internet wird berichtet, dass dieser Wert zwischen 5 und 10 % liegen kann. Es hängt von den Anwendungen innerhalb der virtuellen Maschine und von der Last ab, die sie auf ihre physischen Geräte ausübt. Hier ist es wichtig, darauf zu achten, wie sich die Anwendungen innerhalb der virtuellen Maschinen verhalten.
- Das Verhältnis von Last auf dem Hypervisor und Steal innerhalb der virtuellen Maschine ist nicht immer eindeutig miteinander verbunden; beide Werte für Steal können in bestimmten Situationen bei unterschiedlichen Lasten fehlerhaft sein.
- Der Scheduler hat eine negative Einstellung gegenüber Prozessen, die viel anfordern. Er versucht, weniger Ressourcen an diejenigen zu vergeben, die mehr anfordern. Große virtuelle Maschinen sind problematisch.
- Ein geringfügiger Steal kann auch ohne Paravirtualisierung normal sein (unter Berücksichtigung der Last innerhalb der virtuellen Maschine, der Besonderheiten der Lasten benachbarter Maschinen, der Verteilung der Last auf die Threads und anderer Faktoren).
- Wenn Sie den Steal in einem bestimmten System feststellen möchten, müssen verschiedene Optionen untersucht, Metriken gesammelt, sorgfältig analysiert und Überlegungen angestellt werden, wie die Last gleichmäßig verteilt werden kann. Abweichungen von jeglichen Szenarien müssen experimentell bestätigt oder im Kernel-Debugger überprüft werden.
Quelle: habr.com
