Steal: wie steelt CPU-tijd van virtuele machines

Steal: wie steelt CPU-tijd van virtuele machines

Hallo! Ik wil je in eenvoudige bewoordingen vertellen over de mechanismen van stelen in virtuele machines en over enkele niet voor de hand liggende artefacten die we hebben ontdekt tijdens het onderzoek, waar ik in moest duiken als technisch directeur van een cloudplatform Mail.ru Cloud-oplossingen. Het platform draait op KVM.

CPU-steltijd is de tijd waarin de virtuele machine geen processorbronnen ontvangt voor de uitvoering ervan. Deze tijd wordt alleen geteld in gastbesturingssystemen in virtualisatieomgevingen. De redenen voor waar deze meest toegewezen middelen naartoe gaan, zoals in het leven, zijn erg vaag. Maar we besloten het uit te zoeken en voerden zelfs een aantal experimenten uit. Het is niet zo dat we nu alles weten over stelen, maar we zullen je nu iets interessants vertellen.

1. Wat is stelen

Stelen is dus een maatstaf die wijst op een gebrek aan processortijd voor processen binnen een virtuele machine. Zoals beschreven in de KVM-kernelpatchStealth is de tijd waarin de hypervisor andere processen op het host-besturingssysteem uitvoert, ook al heeft het proces van de virtuele machine in de wachtrij gestaan ​​voor uitvoering. Dat wil zeggen dat stelen wordt berekend als het verschil tussen het tijdstip waarop het proces klaar is om te worden uitgevoerd en het tijdstip waarop aan het proces processortijd wordt toegewezen.

De kernel van de virtuele machine ontvangt de steelmetriek van de hypervisor. Tegelijkertijd specificeert de hypervisor niet precies welke andere processen hij uitvoert, maar zegt hij eenvoudigweg: "terwijl ik bezig ben, kan ik je geen tijd geven." Op KVM is ondersteuning voor diefstalberekening toegevoegd pleisters. Er zijn hier twee belangrijke punten:

  • De virtuele machine leert over stelen van de hypervisor. Dat wil zeggen, vanuit het oogpunt van verliezen is dit voor processen op de virtuele machine zelf een indirecte meting die onderhevig kan zijn aan verschillende vervormingen.
  • De hypervisor deelt geen informatie met de virtuele machine over wat hij nog meer doet - het belangrijkste is dat hij er geen tijd aan besteedt. Hierdoor kan de virtuele machine zelf geen vervormingen in de steelindicator detecteren, die kunnen worden beoordeeld aan de hand van de aard van concurrerende processen.

2. Wat beïnvloedt stelen?

2.1. Berekening stelen

In wezen wordt stelen ongeveer op dezelfde manier berekend als de normale CPU-gebruikstijd. Er is niet veel informatie over hoe recycling wordt beschouwd. Waarschijnlijk omdat de meeste mensen deze vraag voor de hand liggend vinden. Maar er zijn ook valkuilen hier. Om vertrouwd te raken met dit proces, kunt u lezen artikel door Brendan Gregg: u leert over veel nuances bij het berekenen van het gebruik en over situaties waarin deze berekening om de volgende redenen onjuist zal zijn:

  • De processor raakt oververhit, waardoor cycli worden overgeslagen.
  • Schakel turboboost in/uit, waardoor de kloksnelheid van de processor wordt gewijzigd.
  • Een verandering in de lengte van het tijdsegment dat optreedt bij het gebruik van energiebesparende processortechnologieën zoals SpeedStep.
  • Het probleem met het berekenen van het gemiddelde: het schatten van een gebruiksduur van één minuut op 80% kan een kortetermijnuitbarsting van 100% verbergen.
  • Een spin lock zorgt ervoor dat de processor wordt teruggewonnen, maar het gebruikersproces ziet geen voortgang in de uitvoering ervan. Als gevolg hiervan zal het berekende processorgebruik door het proces honderd procent zijn, hoewel het proces fysiek geen processortijd zal verbruiken.

Ik heb geen artikel gevonden waarin een soortgelijke berekening voor stelen wordt beschreven (als je het weet, deel het dan in de reacties). Maar afgaande op de broncode is het berekeningsmechanisme hetzelfde als voor recycling. Er wordt eenvoudigweg een andere teller in de kernel toegevoegd, rechtstreeks voor het KVM-proces (virtueel machineproces), die de duur telt van het KVM-proces dat wacht op CPU-tijd. De teller haalt informatie over de processor uit de specificatie en controleert of al zijn ticks worden gebruikt door het virtuele machineproces. Als dat alles is, gaan we ervan uit dat de processor alleen bezig was met het virtuele machineproces. Anders informeren we dat de processor iets anders deed, er verscheen diefstal.

Het proces van het tellen van staal is onderhevig aan dezelfde problemen als het tellen van reguliere recycling. Dit wil niet zeggen dat dergelijke problemen vaak voorkomen, maar ze zien er ontmoedigend uit.

2.2. Soorten virtualisatie op KVM

Globaal gesproken zijn er drie soorten virtualisatie, die allemaal door KVM worden ondersteund. Het mechanisme achter het ontstaan ​​van diefstal kan afhankelijk zijn van het type virtualisatie.

vertaling. In dit geval vindt de werking van het besturingssysteem van de virtuele machine met fysieke hypervisorapparaten ongeveer als volgt plaats:

  1. Het gastbesturingssysteem stuurt een opdracht naar zijn gastapparaat.
  2. Het gastapparaatstuurprogramma ontvangt de opdracht, genereert een verzoek voor het BIOS van het apparaat en stuurt dit naar de hypervisor.
  3. Het hypervisorproces vertaalt commando naar commando voor het fysieke apparaat, waardoor het onder andere veiliger wordt.
  4. Het fysieke apparaatstuurprogramma accepteert de gewijzigde opdracht en stuurt deze naar het fysieke apparaat zelf.
  5. De resultaten van het uitvoeren van opdrachten gaan langs hetzelfde pad terug.

Het voordeel van vertaling is dat u elk apparaat kunt emuleren en dat er geen speciale voorbereiding van de kernel van het besturingssysteem vereist is. Maar hiervoor moet je in de eerste plaats in snelheid betalen.

Hardwarevirtualisatie. In dit geval begrijpt het apparaat op hardwareniveau opdrachten van het besturingssysteem. Dit is de snelste en beste manier. Maar helaas wordt het niet door alle fysieke apparaten, hypervisors en gastbesturingssystemen ondersteund. Momenteel zijn de belangrijkste apparaten die hardwarevirtualisatie ondersteunen processors.

Paravirtualisatie. De meest gebruikelijke optie voor apparaatvirtualisatie op KVM en over het algemeen de meest gebruikelijke virtualisatiemodus voor gastbesturingssystemen. Het bijzondere is dat het werken met sommige hypervisor-subsystemen (bijvoorbeeld met het netwerk of de schijfstack) of de toewijzing van geheugenpagina's plaatsvindt met behulp van de hypervisor-API, zonder opdrachten op laag niveau te vertalen. Het nadeel van deze virtualisatiemethode is dat de kernel van het gastbesturingssysteem moet worden aangepast zodat deze via deze API met de hypervisor kan communiceren. Maar dit wordt meestal opgelost door speciale stuurprogramma's op het gastbesturingssysteem te installeren. In KVM wordt deze API aangeroepen virtuele API.

Met paravirtualisatie wordt, vergeleken met broadcasting, het pad naar het fysieke apparaat aanzienlijk verkort door opdrachten rechtstreeks van de virtuele machine naar het hypervisorproces op de host te verzenden. Hierdoor kunt u de uitvoering van alle instructies binnen de virtuele machine versnellen. In KVM wordt dit gedaan door de virtio API, die alleen voor bepaalde apparaten werkt, zoals een netwerk- of schijfadapter. Dit is de reden waarom virtio-stuurprogramma's in virtuele machines worden geïnstalleerd.

Het nadeel van deze versnelling is dat niet alle processen die binnen de virtuele machine draaien, daarin blijven. Dit creëert een aantal speciale effecten die kunnen resulteren in spawnen bij stelen. Ik raad aan om een ​​gedetailleerde studie van dit probleem te starten Een API voor virtuele I/O: virtio.

2.3. "Eerlijke" planning

Een virtuele machine op een hypervisor is in feite een gewoon proces dat voldoet aan de wetten van planning (verdeling van bronnen tussen processen) in de Linux-kernel, dus laten we er eens nader naar kijken.

Linux gebruikt de zogenaamde CFS, Completely Fair Scheduler, die sinds kernel 2.6.23 de standaardplanner is geworden. Om dit algoritme te begrijpen, kun je de Linux Kernel Architecture of de broncode lezen. De essentie van CFS is om de processortijd tussen processen te verdelen, afhankelijk van de duur van hun uitvoering. Hoe meer CPU-tijd een proces nodig heeft, hoe minder CPU-tijd het ontvangt. Dit zorgt ervoor dat alle processen "eerlijk" worden uitgevoerd - zodat één proces niet voortdurend alle processors bezet, en andere processen ook kunnen worden uitgevoerd.

Soms leidt dit paradigma tot interessante artefacten. Oude Linux-gebruikers herinneren zich waarschijnlijk het vastlopen van een gewone teksteditor op een desktop terwijl er resource-intensieve applicaties zoals een compiler werden uitgevoerd. Dit gebeurde omdat niet-bronintensieve taken in desktoptoepassingen concurreerden met bronintensieve taken, zoals de compiler. CFS vindt dit oneerlijk, dus stopt het periodiek de teksteditor en laat de processor de taken van de compiler afhandelen. Dit werd gecorrigeerd met behulp van een mechanisme schema_autogroup, maar veel andere kenmerken van de verdeling van processortijd tussen taken bleven bestaan. Eigenlijk is dit geen verhaal over hoe slecht alles is bij CVS, maar een poging om de aandacht te vestigen op het feit dat een “eerlijke” verdeling van de processortijd niet de meest triviale taak is.

Een ander belangrijk punt in de planner is voorrang. Dit is nodig om het gniffelproces uit de processor te bannen en anderen hun werk te laten doen. Het uitwerpproces wordt contextwisseling genoemd. In dit geval blijft de volledige context van de taak behouden: de status van de stapel, registers, enz., waarna het proces wordt gestuurd om te wachten en een ander zijn plaats inneemt. Dit is een dure operatie voor het besturingssysteem en wordt zelden gebruikt, maar er is op zichzelf niets mis mee. Regelmatig wisselen van context kan duiden op een probleem in het besturingssysteem, maar meestal is dit continu en duidt het niet op iets bijzonders.

Er is zo'n lang verhaal nodig om één feit uit te leggen: hoe meer processorbronnen een proces probeert te verbruiken in een eerlijke Linux-planner, hoe sneller het zal worden gestopt, zodat andere processen ook kunnen werken. Of dit juist is of niet, is een complexe vraag die onder verschillende belastingen verschillend kan worden opgelost. In Windows was de planner tot voor kort gericht op de prioriteitsverwerking van desktopapplicaties, waardoor achtergrondprocessen konden vastlopen. Sun Solaris had vijf verschillende klassen planners. Toen we virtualisatie lanceerden, hebben we een zesde toegevoegd: Planner voor eerlijke aandelen, omdat de vorige vijf niet voldoende werkten met Solaris Zones-virtualisatie. Ik raad aan om een ​​gedetailleerde studie van dit probleem te beginnen met boeken als Solaris Internals: Solaris 10 en OpenSolaris Kernel-architectuur of Inzicht in de Linux-kernel.

2.4. Hoe diefstal controleren?

Het monitoren van diefstal in een virtuele machine is, net als elke andere processormetriek, eenvoudig: u kunt elk hulpmiddel voor processormetrieken gebruiken. Het belangrijkste is dat de virtuele machine op Linux staat. Om de een of andere reden verstrekt Windows deze informatie niet aan zijn gebruikers. 🙁

Steal: wie steelt CPU-tijd van virtuele machines
Uitvoer van het bovenste commando: details van de processorbelasting, in de meest rechtse kolom - stelen

De moeilijkheid doet zich voor bij het proberen deze informatie van de hypervisor te verkrijgen. U kunt bijvoorbeeld proberen diefstal op de hostmachine te voorspellen met behulp van de parameter Load Average (LA): de gemiddelde waarde van het aantal processen dat in de uitvoeringswachtrij wacht. De methode voor het berekenen van deze parameter is niet eenvoudig, maar als LA, genormaliseerd door het aantal processorthreads, meer dan 1 is, geeft dit in het algemeen aan dat de Linux-server ergens mee overbelast is.

Waar wachten al deze processen op? Het voor de hand liggende antwoord is de processor. Maar het antwoord is niet helemaal juist, want soms is de processor gratis, maar LA gaat buiten de schaal. Herinneren hoe NFS afvalt en hoe LA groeit. Hetzelfde kan gebeuren met een schijf en andere invoer-/uitvoerapparaten. Maar in feite kunnen processen wachten op het einde van elke blokkering, hetzij fysiek, gekoppeld aan een I/O-apparaat, hetzij logisch, zoals een mutex. Dit omvat ook vergrendeling op het niveau van hardware (dezelfde reactie van de schijf) of logica (de zogenaamde vergrendelingsprimitieven, die een aantal entiteiten omvatten, mutex adaptief en spin, semaforen, conditievariabelen, rw locks, ipc locks ...).

Een ander kenmerk van LA is dat het wordt beschouwd als een besturingssysteemgemiddelde. Er strijden bijvoorbeeld 100 processen om één bestand, en dan LA=50. Een dergelijke hoge waarde lijkt erop te wijzen dat het besturingssysteem slecht is. Maar voor andere slecht geschreven code kan dit een normale toestand zijn, ondanks het feit dat deze alleen slecht is en dat andere processen in het besturingssysteem er niet onder lijden.

Vanwege deze middeling (en in niet minder dan een minuut) is het bepalen van iets aan de hand van de LA-indicator niet de meest lonende taak, met zeer onzekere resultaten in specifieke gevallen. Als je het probeert uit te zoeken, zul je merken dat artikelen op Wikipedia en andere beschikbare bronnen alleen de eenvoudigste gevallen beschrijven, zonder een diepgaande uitleg van het proces. Ik stuur iedereen die geïnteresseerd is nogmaals, hier voor Brendan Gregg  - volg de onderstaande links. Wie is te lui om Engels te spreken - vertaling van zijn populaire artikel over LA.

3. Speciale effecten

Laten we nu eens kijken naar de belangrijkste gevallen van diefstal die we tegenkwamen. Ik zal je vertellen hoe ze uit al het bovenstaande volgen en hoe ze zich verhouden tot de indicatoren op de hypervisor.

Recycling. De eenvoudigste en meest voorkomende: de hypervisor is hergebruikt. Er zijn inderdaad veel virtuele machines actief, er zit een hoog processorverbruik in, er is veel concurrentie, het LA-gebruik is meer dan 1 (genormaliseerd door processorthreads). Alles in alle virtuele machines vertraagt. Het stelen dat door de hypervisor wordt verzonden, groeit ook, het is noodzakelijk om de last te herverdelen of iemand uit te schakelen. Over het algemeen is alles logisch en begrijpelijk.

Paravirtualisatie versus afzonderlijke instanties. Er staat slechts één virtuele machine op de hypervisor; deze verbruikt een klein deel ervan, maar produceert een grote I/O-belasting, bijvoorbeeld op schijf. En ergens verschijnt er een klein staaltje in, tot 10% (zoals blijkt uit verschillende experimenten).

De zaak is interessant. Steal verschijnt hier juist vanwege blokkering op het niveau van geparavirtualiseerde stuurprogramma's. Er wordt een interrupt gecreëerd in de virtuele machine, verwerkt door de driver en naar de hypervisor gestuurd. Door de interruptafhandeling op de hypervisor lijkt het voor de virtuele machine op een verzonden verzoek, het is klaar voor uitvoering en wacht op de processor, maar krijgt geen processortijd. Het virtuele meisje denkt dat deze tijd is gestolen.

Dit gebeurt op het moment dat de buffer wordt verzonden, deze gaat naar de kernelruimte van de hypervisor en we beginnen erop te wachten. Hoewel hij vanuit het oogpunt van de virtuele machine onmiddellijk zou moeten terugkeren. Daarom wordt deze tijd volgens het steelberekeningsalgoritme als gestolen beschouwd. Hoogstwaarschijnlijk kunnen er in deze situatie andere mechanismen zijn (bijvoorbeeld het verwerken van enkele andere systeemoproepen), maar deze zouden niet veel anders moeten zijn.

Scheduler versus zwaarbelaste virtuele machines. Wanneer de ene virtuele machine meer last heeft van diefstal dan de andere, komt dit door de planner. Hoe meer een proces de processor belast, hoe eerder de planner deze eruit gooit, zodat de andere ook kunnen werken. Als de virtuele machine weinig verbruikt, zal hij nauwelijks stelen zien: het proces zat eerlijk gezegd te wachten, we moeten het meer tijd geven. Als een virtuele machine de maximale belasting op al zijn kernen produceert, wordt deze vaak uit de processor gezet en proberen ze er niet veel tijd aan te besteden.

Het is zelfs nog erger wanneer processen binnen de virtuele machine meer processors proberen te krijgen, omdat ze de gegevensverwerking niet aankunnen. Dan zal het besturingssysteem op de hypervisor, door eerlijke optimalisatie, steeds minder processortijd leveren. Dit proces vindt plaats als een lawine en steelt sprongen in de lucht, hoewel andere virtuele machines dit misschien nauwelijks merken. En hoe meer kernen, hoe slechter de getroffen machine. Kortom, zwaarbelaste virtuele machines met veel kernen lijden het meest.

Lage LA, maar er is diefstal. Als LA ongeveer 0,7 is (dat wil zeggen dat de hypervisor onderbelast lijkt te zijn), maar er wordt stelen waargenomen binnen individuele virtuele machines:

  • De optie met paravirtualisatie is hierboven al beschreven. De virtuele machine kan statistieken ontvangen die wijzen op diefstal, hoewel de hypervisor prima werkt. Volgens de resultaten van onze experimenten bedraagt ​​deze optie om te stelen niet meer dan 10% en zou deze geen significante impact moeten hebben op de prestaties van applicaties binnen de virtuele machine.
  • De LA-parameter wordt onjuist berekend. Preciezer gezegd: op elk specifiek moment wordt het correct berekend, maar gemiddeld over een minuut blijkt het een onderschatting te zijn. Als bijvoorbeeld één virtuele machine per derde van de hypervisor al zijn processors precies een halve minuut verbruikt, dan zal LA per minuut op de hypervisor 0,15 zijn; vier van dergelijke virtuele machines die gelijktijdig werken, leveren 0,6 op. En het feit dat er gedurende een halve minuut op elk van hen een wilde diefstal plaatsvond van 25% volgens de LA-indicator, kan niet langer worden teruggetrokken.
  • Nogmaals, vanwege de planner die besloot dat iemand te veel at en die iemand liet wachten. In de tussentijd verander ik de context, handel ik interrupts af en zorg ik voor andere belangrijke systeemzaken. Als gevolg hiervan ondervinden sommige virtuele machines geen problemen, terwijl andere een ernstige prestatievermindering ervaren.

4. Andere vervormingen

Er zijn nog een miljoen redenen om het eerlijke rendement van de processortijd op een virtuele machine te verstoren. Hyperthreading en NUMA zorgen bijvoorbeeld voor problemen bij berekeningen. Ze verwarren de keuze van de kernel voor het uitvoeren van het proces volledig, omdat de planner coëfficiënten - gewichten gebruikt, die de berekening nog moeilijker maken bij het wisselen van context.

Er zijn vervormingen als gevolg van technologieën zoals de turboboost of, omgekeerd, de energiebesparende modus, die bij het berekenen van het gebruik de frequentie of zelfs de tijdsperiode op de server kunstmatig kunnen verhogen of verlagen. Het inschakelen van turboboost vermindert de prestaties van de ene processorthread als gevolg van een toename van de prestaties van een andere. Op dit moment wordt er geen informatie over de huidige processorfrequentie naar de virtuele machine verzonden en wordt aangenomen dat iemand zijn tijd steelt (hij vroeg bijvoorbeeld om 2 GHz, maar ontving de helft daarvan).

Over het algemeen kunnen er veel redenen zijn voor vervorming. Mogelijk vindt u iets anders op een bepaald systeem. Het is beter om te beginnen met de boeken waarnaar ik hierboven links heb gegeven, en statistieken van de hypervisor op te halen met behulp van hulpprogramma's zoals perf, sysdig, systemtap, waarvan tientallen.

5. Conclusies

  1. Er kan een zekere mate van diefstal optreden als gevolg van paravirtualisatie, en dit kan als normaal worden beschouwd. Ze schrijven op internet dat deze waarde 5-10% kan zijn. Hangt af van de applicaties binnen de virtuele machine en van de belasting die deze op de fysieke apparaten legt. Hier is het belangrijk om aandacht te besteden aan hoe applicaties zich voelen in virtuele machines.
  2. De verhouding tussen de belasting van de hypervisor en het stelen binnen de virtuele machine zijn niet altijd duidelijk met elkaar verbonden; beide schattingen van stelen kunnen in specifieke situaties onder verschillende belastingen onjuist zijn.
  3. De planner heeft een slechte houding tegenover processen die veel vragen. Hij probeert minder te geven aan degenen die om meer vragen. Grote virtuele machines zijn slecht.
  4. Een beetje stelen kan de norm zijn, zelfs zonder paravirtualisatie (rekening houdend met de belasting binnen de virtuele machine, de kenmerken van de belasting van buren, belastingverdeling over threads en andere factoren).
  5. Als je diefstal in een specifiek systeem wilt achterhalen, moet je verschillende opties verkennen, statistieken verzamelen, deze zorgvuldig analyseren en nadenken over hoe je de belasting gelijkmatig kunt verdelen. Afwijkingen van alle gevallen zijn mogelijk, die experimenteel moeten worden bevestigd of bekeken in de kernel-debugger.

Bron: www.habr.com

Voeg een reactie