Stjäl: vem stjäl processortid från virtuella maskiner

Stjäl: vem stjäl processortid från virtuella maskiner

Hallå! Jag vill i enkla ordalag berätta om mekaniken för att stjäla inuti virtuella maskiner och om några icke-uppenbara artefakter som vi lyckades ta reda på under dess forskning, som jag var tvungen att dyka in i som teknisk chef för en molnplattform Mail.ru molnlösningar. Plattformen körs på KVM.

CPU-stöldtid är den tid under vilken den virtuella maskinen inte tar emot processorresurser för sin exekvering. Denna tid räknas endast i gästoperativsystem i virtualiseringsmiljöer. Orsakerna till vart dessa mest allokerade resurser går, som i livet, är mycket vaga. Men vi bestämde oss för att ta reda på det och gjorde till och med ett antal experiment. Det är inte så att vi nu vet allt om att stjäla, men vi ska berätta något intressant nu.

1. Vad är stjäla

Så stjäla är ett mått som indikerar brist på processortid för processer inuti en virtuell maskin. Som beskriven i KVM-kärnpatchenStealth är den tid under vilken hypervisorn kör andra processer på värdoperativsystemet trots att den har ställt den virtuella maskinens process i kö för exekvering. Det vill säga att stjäla beräknas som skillnaden mellan den tid då processen är redo att utföras och den tid då processen tilldelas processortid.

Den virtuella maskinens kärna tar emot stöldmåttet från hypervisorn. Samtidigt anger inte hypervisorn exakt vilka andra processer den körs, den säger bara "medan jag är upptagen kan jag inte ge dig tid." På KVM har stöd för stöldberäkning lagts till plåster. Det finns två nyckelpunkter här:

  • Den virtuella maskinen lär sig om att stjäla från hypervisorn. Det vill säga, ur förlustsynpunkt, för processer på själva den virtuella maskinen är detta en indirekt mätning som kan utsättas för olika förvrängningar.
  • Hypervisorn delar inte information med den virtuella maskinen om vad den gör mer - huvudsaken är att den inte ägnar tid åt det. På grund av detta kan den virtuella maskinen själv inte upptäcka förvrängningar i stöldindikatorn, vilket kan bedömas av konkurrerande processers natur.

2. Vad påverkar stjäla

2.1. Stjäla beräkning

I huvudsak beräknas stjäla ungefär som den normala CPU-användningstiden. Det finns inte mycket information om hur återvinning betraktas. Förmodligen för att de flesta anser att denna fråga är självklar. Men här finns också fallgropar. För att bekanta dig med denna process kan du läsa artikel av Brendan Gregg: du kommer att lära dig om många nyanser vid beräkning av utnyttjande och om situationer när denna beräkning kommer att vara felaktig av följande skäl:

  • Processorn överhettas, vilket gör att cykler hoppar över.
  • Aktivera/inaktivera turboboost, som ändrar processorns klockfrekvens.
  • En förändring av längden på tidsdelen som inträffar när du använder processorenergibesparande teknologier som SpeedStep.
  • Problemet med att beräkna genomsnittet: att uppskatta en minuts utnyttjande till 80 % kan dölja en kortsiktig skur på 100 %.
  • Ett spinnlås gör att processorn återtas, men användarprocessen ser inga framsteg i dess exekvering. Som ett resultat kommer det beräknade processorutnyttjandet av processen att vara hundra procent, även om processen inte fysiskt kommer att förbruka processortid.

Jag har inte hittat en artikel som beskriver en liknande beräkning för stjäla (om du vet, dela den i kommentarerna). Men av källkoden att döma är beräkningsmekanismen densamma som för återvinning. Helt enkelt, ytterligare en räknare läggs till i kärnan, direkt för KVM-processen (virtuell maskinprocess), som räknar hur länge KVM-processen väntar på CPU-tid. Räknaren hämtar information om processorn från dess specifikation och kontrollerar om alla dess markeringar används av den virtuella maskinens process. Om det är allt, antar vi att processorn bara var upptagen med den virtuella maskinprocessen. Annars informerar vi om att processorn gjorde något annat, stjäl dök upp.

Processen för stöldräkning är föremål för samma problem som vanlig återvinningsräkning. För att inte säga att sådana problem dyker upp ofta, men de ser nedslående ut.

2.2. Typer av virtualisering på KVM

I stort sett finns det tre typer av virtualisering, som alla stöds av KVM. Mekanismen för att stjäla kan bero på typen av virtualisering.

översättning. I det här fallet sker driften av den virtuella maskinens operativsystem med fysiska hypervisorenheter ungefär så här:

  1. Gästoperativsystemet skickar ett kommando till sin gästenhet.
  2. Gästdrivrutinen tar emot kommandot, genererar en begäran om enhetens BIOS och skickar den till hypervisorn.
  3. Hypervisorprocessen översätter kommando till kommando för den fysiska enheten, vilket gör den bland annat säkrare.
  4. Den fysiska enhetsdrivrutinen accepterar det modifierade kommandot och skickar det till den fysiska enheten själv.
  5. Resultaten av att utföra kommandon går tillbaka längs samma väg.

Fördelen med översättning är att den låter dig emulera vilken enhet som helst och kräver ingen speciell förberedelse av operativsystemets kärna. Men du måste betala för detta, först och främst i hastighet.

Hårdvaruvirtualisering. I det här fallet förstår enheten på hårdvarunivå kommandon från operativsystemet. Detta är det snabbaste och bästa sättet. Men tyvärr stöds det inte av alla fysiska enheter, hypervisorer och gästoperativsystem. För närvarande är de huvudsakliga enheterna som stöder hårdvaruvirtualisering processorer.

Paravirtualisering. Det vanligaste alternativet för enhetsvirtualisering på KVM och generellt det vanligaste virtualiseringsläget för gästoperativsystem. Dess egenhet är att arbete med vissa hypervisorundersystem (till exempel med nätverket eller diskstacken) eller allokering av minnessidor sker med hjälp av hypervisor API, utan att översätta kommandon på låg nivå. Nackdelen med denna virtualiseringsmetod är att gästoperativsystemets kärna måste modifieras så att den kan kommunicera med hypervisorn med hjälp av detta API. Men detta löses vanligtvis genom att installera speciella drivrutiner på gästoperativsystemet. I KVM kallas detta API virtio API.

Med paravirtualisering, jämfört med broadcasting, reduceras vägen till den fysiska enheten avsevärt genom att skicka kommandon direkt från den virtuella maskinen till hypervisorprocessen på värden. Detta gör att du kan påskynda exekveringen av alla instruktioner inuti den virtuella maskinen. I KVM görs detta av virtio API, som bara fungerar för vissa enheter, till exempel ett nätverk eller en diskadapter. Det är därför virtio-drivrutiner är installerade i virtuella maskiner.

Nackdelen med denna acceleration är att inte alla processer som körs inuti den virtuella maskinen finns kvar i den. Detta skapar några specialeffekter som kan resultera i spawning vid stjäl. Jag rekommenderar att du påbörjar en detaljerad studie av denna fråga med Ett API för virtuell I/O: virtio.

2.3. "Rättvis" schemaläggning

En virtuell maskin på en hypervisor är i själva verket en vanlig process som följer lagarna för schemaläggning (resursfördelning mellan processer) i Linux-kärnan, så låt oss titta närmare på det.

Linux använder den så kallade CFS, Completely Fair Scheduler, som har blivit standardschemaläggaren sedan kärnan 2.6.23. För att förstå denna algoritm kan du läsa Linux Kernel Architecture eller källkoden. Kärnan i CFS är att fördela processortid mellan processer beroende på hur länge de körs. Ju mer CPU-tid en process kräver, desto mindre CPU-tid tar den emot. Detta säkerställer att alla processer exekveras "rättvist" - så att en process inte ständigt upptar alla processorer, och andra processer kan också exekveras.

Ibland leder detta paradigm till intressanta artefakter. Långa Linux-användare kommer förmodligen ihåg hur en vanlig textredigerare fryste på ett skrivbord när de körde resurskrävande applikationer som en kompilator. Detta hände eftersom icke-resurskrävande uppgifter i skrivbordsapplikationer konkurrerade med resurskrävande uppgifter, som kompilatorn. CFS tycker att detta är orättvist, så det stoppar regelbundet textredigeraren och låter processorn hantera kompilatorns uppgifter. Detta korrigerades med hjälp av en mekanism sched_autogroup, men många andra funktioner i fördelningen av processortid mellan uppgifter kvarstod. Egentligen är detta inte en historia om hur dåligt allt är i CFS, utan ett försök att uppmärksamma det faktum att "rättvis" fördelning av processortid inte är den mest triviala uppgiften.

En annan viktig punkt i schemaläggaren är preemption. Det här är nödvändigt för att sparka bort skrattprocessen från processorn och låta andra arbeta. Utmatningsprocessen kallas kontextväxling. I det här fallet bevaras hela sammanhanget för uppgiften: stackens tillstånd, register etc., varefter processen skickas för att vänta och en annan tar dess plats. Detta är en dyr operation för operativsystemet och används sällan, men det är inget fel med det. Frekvent kontextväxling kan indikera ett problem i operativsystemet, men vanligtvis är det kontinuerligt och indikerar inget särskilt.

En så lång historia behövs för att förklara ett faktum: ju mer processorresurser en process försöker konsumera i en ärlig Linux-schemaläggare, desto snabbare kommer den att stoppas så att andra processer också kan fungera. Om detta är korrekt eller inte är en komplex fråga som kan lösas olika under olika belastningar. I Windows, tills nyligen, var schemaläggaren fokuserad på prioriterad bearbetning av skrivbordsapplikationer, vilket kan få bakgrundsprocesser att frysa. Sun Solaris hade fem olika klasser av schemaläggare. När vi lanserade virtualisering lade vi till en sjätte, Schemaläggare för rättvis andel, eftersom de tidigare fem inte fungerade tillräckligt med Solaris Zones-virtualisering. Jag rekommenderar att du påbörjar en detaljerad studie av denna fråga med böcker som Solaris Internals: Solaris 10 och OpenSolaris Kernel Architecture eller Förstå Linux-kärnan.

2.4. Hur övervakar man stjäla?

Att övervaka stjäl inuti en virtuell maskin, precis som alla andra processormått, är enkelt: du kan använda vilket processormått som helst. Huvudsaken är att den virtuella maskinen är på Linux. Av någon anledning tillhandahåller inte Windows denna information till sina användare. 🙁

Stjäl: vem stjäl processortid från virtuella maskiner
Utdata från toppkommandot: detaljer om processorbelastningen, i kolumnen längst till höger - stjäla

Svårigheten uppstår när man försöker få denna information från hypervisorn. Du kan försöka förutsäga stjäla på värddatorn, till exempel genom att använda parametern Load Average (LA) - medelvärdet av antalet processer som väntar i exekveringskön. Metoden för att beräkna denna parameter är inte enkel, men i allmänhet, om LA normaliserad med antalet processortrådar är mer än 1, indikerar detta att Linux-servern är överbelastad med något.

Vad väntar alla dessa processer på? Det uppenbara svaret är processorn. Men svaret är inte helt korrekt, för ibland är processorn ledig, men LA går ur skala. Kom ihåg hur NFS faller av och hur LA växer. Detsamma kan hända med en disk och andra in-/utgångsenheter. Men i själva verket kan processer vänta på slutet av alla lås, antingen fysiska, associerade med en I/O-enhet eller logiska, till exempel en mutex. Detta inkluderar även låsning på hårdvarunivå (samma svar från disken), eller logik (de så kallade låsningsprimitiv, som inkluderar ett gäng entiteter, mutex adaptiva och spin, semaforer, tillståndsvariabler, rw-lås, ipc-lås ...).

En annan egenskap hos LA är att den betraktas som ett operativsystemgenomsnitt. Till exempel konkurrerar 100 processer om en fil, och sedan LA=50. Ett så stort värde verkar tyda på att operativsystemet är dåligt. Men för annan snett skriven kod kan detta vara ett normalt tillstånd, trots att bara det är dåligt, och andra processer i operativsystemet inte lider.

På grund av detta medelvärde (och på inte mindre än en minut) är det inte den mest givande uppgiften att bestämma någonting med LA-indikatorn, med mycket osäkra resultat i specifika fall. Om du försöker lista ut det kommer du att upptäcka att artiklar på Wikipedia och andra tillgängliga resurser endast beskriver de enklaste fallen, utan en djupgående förklaring av processen. Jag skickar alla som är intresserade, igen, här till Brendan Gregg  - följ länkarna nedan. Vem är för lat för att prata engelska - översättning av hans populära artikel om LA.

3. Specialeffekter

Låt oss nu titta på de viktigaste fallen av stöld som vi stötte på. Jag ska berätta hur de följer av allt ovan och hur de relaterar till indikatorerna på hypervisorn.

Återvinning. Det enklaste och vanligaste: hypervisorn har återanvänts. Det finns faktiskt många virtuella maskiner som körs, hög processorförbrukning inuti dem, mycket konkurrens, LA-användningen är mer än 1 (normaliserat av processortrådar). Allt inuti alla virtuella maskiner saktar ner. Stjäla som överförs från hypervisorn växer också, det är nödvändigt att omfördela belastningen eller stänga av någon. I allmänhet är allt logiskt och förståeligt.

Paravirtualisering kontra enstaka instanser. Det finns bara en virtuell maskin på hypervisorn, den förbrukar en liten del av den, men producerar en stor I/O-belastning, till exempel på disk. Och från någonstans dyker det upp en liten stjäla i den, upp till 10% (som visas av flera experiment).

Fallet är intressant. Steal dyker upp här just på grund av blockering på nivån av paravirtualiserade drivrutiner. Ett avbrott skapas inuti den virtuella maskinen, bearbetas av föraren och skickas till hypervisorn. På grund av avbrottshanteringen på hypervisorn ser det för den virtuella maskinen ut som en skickad begäran, den är klar för exekvering och väntar på processorn, men den får inte processortid. Den virtuella tjejen tror att den här gången har blivit stulen.

Detta händer i det ögonblick som bufferten skickas, den går in i hypervisorns kärnutrymme och vi börjar vänta på det. Även om han, ur den virtuella maskinens synvinkel, borde återvända omedelbart. Därför, enligt beräkningsalgoritmen för stjäl, anses denna tid vara stulen. Troligtvis kan det i den här situationen finnas andra mekanismer (till exempel bearbetning av några andra sys-anrop), men de borde inte vara mycket annorlunda.

Schemaläggare kontra högbelastade virtuella maskiner. När en virtuell maskin lider av att stjäla mer än andra, beror detta på schemaläggaren. Ju mer en process laddar processorn, desto snabbare kommer schemaläggaren att sparka ut den så att de andra också kan fungera. Om den virtuella maskinen förbrukar lite, kommer den knappast att se stjäla: dess process satt ärligt och väntade, vi måste ge den mer tid. Om en virtuell maskin producerar maximal belastning på alla sina kärnor, sparkas den ofta ut ur processorn och de försöker att inte ge den mycket tid.

Det är ännu värre när processer inuti den virtuella maskinen försöker få mer processor eftersom de inte kan hantera databehandling. Då kommer operativsystemet på hypervisorn, på grund av ärlig optimering, att ge allt mindre processortid. Denna process sker som en lavin, och stjäl hoppar till skyarna, även om andra virtuella maskiner knappt märker det. Och ju fler kärnor, desto värre är den drabbade maskinen. Kort sagt, högbelastade virtuella maskiner med många kärnor lider mest.

Låg LA, men det finns stjäl. Om LA är ungefär 0,7 (det vill säga hypervisorn verkar vara underbelastad), men stöld observeras inuti individuella virtuella maskiner:

  • Alternativet med paravirtualisering som redan beskrivits ovan. Den virtuella maskinen kan ta emot mätvärden som indikerar stjäla, även om hypervisorn är bra. Enligt resultaten av våra experiment överstiger inte detta stöldalternativ 10 % och bör inte ha någon betydande inverkan på prestandan för applikationer inuti den virtuella maskinen.
  • LA-parametern är felaktigt beräknad. Närmare bestämt, vid varje specifikt ögonblick beräknas det korrekt, men när det beräknas i genomsnitt över en minut visar det sig vara underskattat. Till exempel, om en virtuell maskin per tredjedel av hypervisorn förbrukar alla sina processorer i exakt en halv minut, så blir LA per minut på hypervisorn 0,15; fyra sådana virtuella maskiner som arbetar samtidigt ger 0,6. Och det faktum att det under en halv minut på var och en av dem skedde en vild stöld på 25 % enligt LA-indikatorn går inte längre att dra ut.
  • Återigen, på grund av schemaläggaren som bestämde att någon åt för mycket och lät den där vänta. Under tiden byter jag sammanhang, hanterar avbrott och tar hand om andra viktiga systemsaker. Som ett resultat ser vissa virtuella maskiner inga problem, medan andra upplever allvarlig prestandaförsämring.

4. Andra snedvridningar

Det finns ytterligare en miljon anledningar till att förvränga rättvis avkastning på processortid på en virtuell maskin. Till exempel introducerar hypertrådning och NUMA svårigheter i beräkningar. De förvirrar helt valet av kärna för att köra processen, eftersom schemaläggaren använder koefficienter - vikter, vilket gör beräkningen ännu svårare när man byter sammanhang.

Det finns snedvridningar på grund av teknologier som turboboost eller omvänt energisparläge, som vid beräkning av utnyttjande kan artificiellt öka eller minska frekvensen eller till och med tidsdelen på servern. Aktivering av turboboost minskar prestandan hos en processortråd på grund av en ökning av prestanda hos en annan. För närvarande överförs inte information om den aktuella processorfrekvensen till den virtuella maskinen, och den tror att någon stjäl dess tid (till exempel begärde den 2 GHz, men fick hälften av det).

I allmänhet kan det finnas många orsaker till förvrängning. Du kan hitta något annat på ett visst system. Det är bättre att börja med böckerna som jag länkade till ovan, och hämta statistik från hypervisorn med hjälp av verktyg som perf, sysdig, systemtap, varav dussintals.

5. Sammanfattningar

  1. En viss mängd stjäl kan inträffa på grund av paravirtualisering, och det kan anses vara normalt. De skriver på Internet att detta värde kan vara 5-10%. Beror på applikationerna inuti den virtuella maskinen och på belastningen den lägger på sina fysiska enheter. Här är det viktigt att vara uppmärksam på hur applikationer känns i virtuella maskiner.
  2. Förhållandet mellan belastningen på hypervisorn och stjälningen inuti den virtuella maskinen är inte alltid tydligt relaterade; båda uppskattningarna av stjälning kan vara felaktiga i specifika situationer under olika belastningar.
  3. Schemaläggaren har en dålig inställning till processer som frågar mycket. Han försöker ge mindre till dem som ber om mer. Stora virtuella maskiner är onda.
  4. Lite stjäl kan vara normen även utan paravirtualisering (med hänsyn till belastningen inuti den virtuella maskinen, egenskaperna hos belastningen hos grannar, belastningsfördelning över trådar och andra faktorer).
  5. Om du vill lista ut att stjäla i ett specifikt system måste du utforska olika alternativ, samla in mätvärden, noggrant analysera dem och tänka på hur du ska fördela belastningen jämnt. Avvikelser från alla fall är möjliga, vilket måste bekräftas experimentellt eller tittas på i kärnfelsökaren.

Källa: will.com

Lägg en kommentar