Steal: chi ruba tempo processore dalle macchine virtuali

Steal: chi ruba tempo processore dalle macchine virtuali

Ciao! Voglio parlarvi in ​​termini semplici dei meccanismi di furto all'interno delle macchine virtuali e di alcuni artefatti non evidenti che siamo riusciti a scoprire durante la sua ricerca, nella quale mi sono dovuto immergere come direttore tecnico di una piattaforma cloud Mail.ru soluzioni cloud. La piattaforma funziona su KVM.

Il tempo di furto della CPU è il tempo durante il quale la macchina virtuale non riceve risorse del processore per la sua esecuzione. Questa volta viene conteggiata solo nei sistemi operativi guest negli ambienti di virtualizzazione. Le ragioni per cui vanno a finire queste risorse più allocate, come nella vita, sono molto vaghe. Ma abbiamo deciso di capirlo e abbiamo anche effettuato una serie di esperimenti. Non è che ormai sappiamo tutto del furto, ma adesso vi raccontiamo una cosa interessante.

1. Cos'è il furto

Pertanto, il furto è una metrica che indica una mancanza di tempo del processore per i processi all'interno di una macchina virtuale. Come descritto nella patch del kernel KVMStealth è il tempo durante il quale l'hypervisor esegue altri processi sul sistema operativo host anche se ha messo in coda il processo della macchina virtuale per l'esecuzione. Cioè, il furto viene calcolato come la differenza tra il momento in cui il processo è pronto per l'esecuzione e il momento in cui al processo viene allocato il tempo del processore.

Il kernel della macchina virtuale riceve la metrica di furto dall'hypervisor. Allo stesso tempo, l’hypervisor non specifica esattamente quali altri processi sta eseguendo, dice semplicemente “mentre sono occupato, non posso darti tempo”. Su KVM è stato aggiunto il supporto per il calcolo del furto cerotti. Ci sono due punti chiave qui:

  • La macchina virtuale apprende il furto dall'hypervisor. Cioè, dal punto di vista delle perdite, per i processi sulla macchina virtuale stessa si tratta di una misurazione indiretta che può essere soggetta a varie distorsioni.
  • L'hypervisor non condivide informazioni con la macchina virtuale su cos'altro sta facendo: l'importante è che non gli dedichi tempo. Per questo motivo la macchina virtuale stessa non è in grado di rilevare distorsioni nell'indicatore di furto, che potrebbero essere valutate dalla natura dei processi concorrenti.

2. Cosa influenza il furto

2.1. Calcolo del furto

In sostanza, il furto viene calcolato più o meno come il normale tempo di utilizzo della CPU. Non ci sono molte informazioni su come viene considerato il riciclaggio. Probabilmente perché la maggior parte delle persone considera questa domanda ovvia. Ma ci sono anche delle insidie ​​​​qui. Per familiarizzare con questo processo, puoi leggere articolo di Brendan Gregg: imparerai molte sfumature nel calcolo dell'utilizzo e le situazioni in cui questo calcolo sarà errato per i seguenti motivi:

  • Il processore si surriscalda, causando il salto dei cicli.
  • Abilita/disabilita il turbo boost, che modifica la velocità di clock del processore.
  • Una modifica nella durata dell'intervallo di tempo che si verifica quando si utilizzano tecnologie di risparmio energetico del processore come SpeedStep.
  • Il problema con il calcolo della media: stimare l'utilizzo di un minuto all'80% può nascondere un'esplosione a breve termine del 100%.
  • Uno spin lock provoca il recupero del processore, ma il processo utente non vede alcun progresso nella sua esecuzione. Di conseguenza, l'utilizzo calcolato del processore da parte del processo sarà pari al XNUMX%, sebbene il processo non consumerà fisicamente il tempo del processore.

Non ho trovato un articolo che descriva un calcolo simile per il furto (se lo sai, condividilo nei commenti). Ma, a giudicare dal codice sorgente, il meccanismo di calcolo è lo stesso del riciclaggio. Semplicemente, nel kernel viene aggiunto un altro contatore, direttamente per il processo KVM (processo della macchina virtuale), che conta la durata del processo KVM in attesa del tempo della CPU. Il contatore prende le informazioni sul processore dalle sue specifiche e controlla se tutti i suoi tick sono utilizzati dal processo della macchina virtuale. Se questo è tutto, supponiamo che il processore fosse occupato solo dal processo della macchina virtuale. Altrimenti, informiamo che il processore stava facendo qualcos'altro, è apparso il furto.

Il processo di conteggio dei furti è soggetto agli stessi problemi del normale conteggio del riciclaggio. Per non dire che tali problemi appaiano spesso, ma sembrano scoraggianti.

2.2. Tipi di virtualizzazione su KVM

In generale, esistono tre tipi di virtualizzazione, tutti supportati da KVM. Il meccanismo di furto può dipendere dal tipo di virtualizzazione.

traduzione. In questo caso, il funzionamento del sistema operativo della macchina virtuale con i dispositivi hypervisor fisici avviene in questo modo:

  1. Il sistema operativo ospite invia un comando al suo dispositivo ospite.
  2. Il driver del dispositivo ospite riceve il comando, genera una richiesta per il BIOS del dispositivo e la invia all'hypervisor.
  3. Il processo dell'hypervisor traduce un comando in comando per il dispositivo fisico, rendendolo, tra le altre cose, più sicuro.
  4. Il driver del dispositivo fisico accetta il comando modificato e lo invia al dispositivo fisico stesso.
  5. I risultati dell'esecuzione dei comandi risalgono lungo lo stesso percorso.

Il vantaggio della traduzione è che permette di emulare qualsiasi dispositivo e non richiede una preparazione particolare del kernel del sistema operativo. Ma questo devi pagare, prima di tutto, in velocità.

Virtualizzazione dell'hardware. In questo caso, il dispositivo a livello hardware comprende i comandi del sistema operativo. Questo è il modo migliore e più veloce. Ma sfortunatamente non è supportato da tutti i dispositivi fisici, hypervisor e sistemi operativi guest. Attualmente, i principali dispositivi che supportano la virtualizzazione dell'hardware sono i processori.

Paravirtualizzazione. L'opzione più comune per la virtualizzazione dei dispositivi su KVM e generalmente la modalità di virtualizzazione più comune per i sistemi operativi guest. La sua particolarità è che il lavoro con alcuni sottosistemi dell'hypervisor (ad esempio, con la rete o lo stack di dischi) o l'allocazione delle pagine di memoria avviene utilizzando l'API dell'hypervisor, senza tradurre comandi di basso livello. Lo svantaggio di questo metodo di virtualizzazione è che il kernel del sistema operativo guest deve essere modificato in modo che possa comunicare con l'hypervisor utilizzando questa API. Ma questo di solito viene risolto installando driver speciali sul sistema operativo guest. In KVM viene chiamata questa API API virtuale.

Con la paravirtualizzazione, rispetto al broadcasting, il percorso verso il dispositivo fisico viene notevolmente ridotto inviando comandi direttamente dalla macchina virtuale al processo hypervisor sull'host. Ciò consente di velocizzare l'esecuzione di tutte le istruzioni all'interno della macchina virtuale. In KVM, questo viene fatto dall'API virtio, che funziona solo per determinati dispositivi, come un adattatore di rete o un disco. Questo è il motivo per cui i driver virtio sono installati all'interno delle macchine virtuali.

Lo svantaggio di questa accelerazione è che non tutti i processi eseguiti all'interno della macchina virtuale rimangono al suo interno. Questo crea alcuni effetti speciali che possono provocare la generazione del furto. Consiglio di iniziare uno studio dettagliato di questo problema con Un'API per I/O virtuale: virtio.

2.3. Programmazione "giusta".

Una macchina virtuale su un hypervisor è, in effetti, un processo ordinario che obbedisce alle leggi della pianificazione (distribuzione delle risorse tra i processi) nel kernel Linux, quindi diamo un'occhiata più da vicino.

Linux utilizza il cosiddetto CFS, Completely Fair Scheduler, che è diventato lo scheduler predefinito a partire dal kernel 2.6.23. Per comprendere questo algoritmo, puoi leggere l'architettura del kernel Linux o il codice sorgente. L'essenza di CFS è distribuire il tempo del processore tra i processi a seconda della durata della loro esecuzione. Maggiore è il tempo CPU richiesto da un processo, minore è il tempo CPU che riceve. Ciò garantisce che tutti i processi vengano eseguiti "equamente", in modo che un processo non occupi costantemente tutti i processori e possano essere eseguiti anche altri processi.

A volte questo paradigma porta a manufatti interessanti. Gli utenti Linux di lunga data probabilmente ricordano il blocco di un normale editor di testo su un desktop durante l'esecuzione di applicazioni ad alta intensità di risorse come un compilatore. Ciò è accaduto perché le attività non ad alta intensità di risorse nelle applicazioni desktop erano in competizione con attività ad alta intensità di risorse, come il compilatore. CFS ritiene che ciò sia ingiusto, quindi interrompe periodicamente l'editor di testo e consente al processore di gestire i compiti del compilatore. Questo è stato corretto utilizzando un meccanismo sched_autogroup, ma sono rimaste molte altre caratteristiche della distribuzione del tempo del processore tra le attività. In realtà, questa non è una storia su quanto tutto sia pessimo in CFS, ma un tentativo di attirare l'attenzione sul fatto che la distribuzione "equa" del tempo del processore non è il compito più banale.

Un altro punto importante nello scheduler è la prelazione. Ciò è necessario per eliminare il processo di risatina dal processore e lasciare che gli altri lavorino. Il processo di espulsione è chiamato cambio di contesto. In questo caso, l'intero contesto dell'attività viene preservato: lo stato dello stack, dei registri, ecc., Dopodiché il processo viene mandato in attesa e un altro ne prende il posto. Questa è un'operazione costosa per il sistema operativo e viene utilizzata raramente, ma non c'è nulla di intrinsecamente sbagliato in essa. Il frequente cambio di contesto può indicare un problema nel sistema operativo, ma di solito è continuo e non indica nulla in particolare.

Una storia così lunga è necessaria per spiegare un fatto: più risorse del processore un processo tenta di consumare in uno scheduler Linux onesto, più velocemente verrà fermato in modo che anche altri processi possano funzionare. Se questo sia corretto o meno è una questione complessa che può essere risolta in modo diverso a seconda dei carichi. In Windows, fino a poco tempo fa, lo scheduler si concentrava sull'elaborazione prioritaria delle applicazioni desktop, che poteva causare il blocco dei processi in background. Sun Solaris aveva cinque diverse classi di scheduler. Quando abbiamo lanciato la virtualizzazione, ne abbiamo aggiunto un sesto, Pianificatore di condivisione equa, perché i cinque precedenti non funzionavano adeguatamente con la virtualizzazione di Solaris Zones. Consiglio di iniziare uno studio dettagliato di questo problema con libri come Componenti interni di Solaris: Solaris 10 e architettura kernel OpenSolaris o Comprensione del kernel Linux.

2.4. Come monitorare i furti?

Monitorare il furto all'interno di una macchina virtuale, come qualsiasi altra metrica del processore, è semplice: puoi utilizzare qualsiasi strumento di metrica del processore. La cosa principale è che la macchina virtuale sia su Linux. Per qualche motivo Windows non fornisce queste informazioni ai propri utenti. 🙁

Steal: chi ruba tempo processore dalle macchine virtuali
Risultato del comando principale: dettagli sul carico del processore, nella colonna più a destra - ruba

La difficoltà sorge quando si tenta di ottenere queste informazioni dall'hypervisor. Puoi provare a prevedere il furto sulla macchina host, ad esempio, utilizzando il parametro Load Average (LA), il valore medio del numero di processi in attesa nella coda di esecuzione. Il metodo per calcolare questo parametro non è semplice, ma in generale, se LA normalizzato per il numero di thread del processore è superiore a 1, ciò indica che il server Linux è sovraccarico di qualcosa.

Cosa aspettano tutti questi processi? La risposta ovvia è il processore. Ma la risposta non è del tutto corretta, perché a volte il processore è libero, ma LA va fuori scala. Ricordare come NFS cade e come cresce LA. Lo stesso può accadere con un disco e altri dispositivi di input/output. Ma in realtà, i processi possono attendere la fine di qualsiasi blocco, sia fisico, associato a un dispositivo di I/O, sia logico, come un mutex. Ciò include anche il blocco a livello hardware (la stessa risposta dal disco) o logico (le cosiddette primitive di blocco, che includono un insieme di entità, mutex adattivo e spin, semafori, variabili di condizione, blocchi rw, blocchi ipc ...).

Un'altra caratteristica di LA è che è considerato un sistema operativo medio. Ad esempio, 100 processi competono per un file e quindi LA=50. Un valore così elevato sembrerebbe indicare che il sistema operativo non funziona bene. Ma per altri codici scritti in modo storto, questo potrebbe essere uno stato normale, nonostante sia solo cattivo e altri processi nel sistema operativo non ne soffrono.

A causa di questa media (e in non meno di un minuto), determinare qualsiasi cosa mediante l’indicatore LA non è il compito più gratificante, con risultati molto incerti in casi specifici. Se provi a capirlo, scoprirai che gli articoli su Wikipedia e altre risorse disponibili descrivono solo i casi più semplici, senza una spiegazione approfondita del processo. Mando di nuovo a tutti coloro che sono interessati, qui a Brendan Gregg  - seguire i link sottostanti. Chi è troppo pigro per parlare inglese - traduzione del suo popolare articolo su Los Angeles.

3. Effetti speciali

Vediamo ora i principali casi di furto che abbiamo riscontrato. Ti dirò come derivano da tutto quanto sopra e come si collegano agli indicatori sull'hypervisor.

Raccolta differenziata. Il più semplice e comune: l'hypervisor è stato riutilizzato. In effetti, ci sono molte macchine virtuali in esecuzione, un elevato consumo di processore al loro interno, molta concorrenza, l'utilizzo di LA è superiore a 1 (normalizzato dai thread del processore). Tutto all'interno di tutte le macchine virtuali rallenta. Crescono anche i furti trasmessi dall'hypervisor, è necessario ridistribuire il carico o spegnere qualcuno. In generale, tutto è logico e comprensibile.

Paravirtualizzazione e istanze singole. Sull'hypervisor è presente una sola macchina virtuale; ne consuma una piccola parte, ma produce un grande carico di I/O, ad esempio su disco. E da qualche parte appare un piccolo furto, fino al 10% (come dimostrato da diversi esperimenti).

Il caso è interessante. Il furto appare qui proprio a causa del blocco a livello dei conducenti paravirtualizzati. All'interno della macchina virtuale viene creato un interrupt, elaborato dal driver e inviato all'hypervisor. A causa della gestione delle interruzioni sull'hypervisor, per la macchina virtuale sembra una richiesta inviata, è pronta per l'esecuzione e attende il processore, ma non gli viene dato il tempo del processore. La ragazza virtuale pensa che questa volta le sia stato rubato.

Ciò accade nel momento in cui il buffer viene inviato, entra nello spazio del kernel dell'hypervisor e iniziamo ad aspettarlo. Anche se, dal punto di vista della macchina virtuale, dovrebbe tornare subito. Pertanto, secondo l'algoritmo di calcolo del furto, questa volta è considerata rubata. Molto probabilmente, in questa situazione potrebbero esserci altri meccanismi (ad esempio, l'elaborazione di altre chiamate di sistema), ma non dovrebbero essere molto diversi.

Scheduler rispetto a macchine virtuali ad alto carico. Quando una macchina virtuale subisce furti più di altre, ciò è dovuto allo scheduler. Più un processo carica il processore, prima lo scheduler lo eliminerà in modo che anche gli altri possano funzionare. Se la macchina virtuale consuma poco, difficilmente vedrà rubare: il suo processo onestamente è rimasto ad aspettare, bisogna dargli più tempo. Se una macchina virtuale produce il carico massimo su tutti i suoi core, spesso viene espulsa dal processore e si cerca di non darle molto tempo.

È ancora peggio quando i processi all’interno della macchina virtuale cercano di ottenere più processore perché non riescono a gestire l’elaborazione dei dati. Quindi il sistema operativo sull'hypervisor, a causa dell'onesta ottimizzazione, fornirà sempre meno tempo al processore. Questo processo avviene come una valanga e ruba salti nel cielo, anche se altre macchine virtuali difficilmente se ne accorgono. E maggiore è il numero di core, peggiore è la macchina colpita. In breve, le macchine virtuali ad alto carico con molti core soffrono di più.

LA bassa, ma c'è furto. Se LA è circa 0,7 (ovvero, l'hypervisor sembra essere sottocaricato), ma si osserva un furto all'interno delle singole macchine virtuali:

  • L'opzione con paravirtualizzazione già descritta sopra. La macchina virtuale può ricevere parametri che indicano il furto, sebbene l'hypervisor funzioni correttamente. Secondo i risultati dei nostri esperimenti, questa opzione di furto non supera il 10% e non dovrebbe avere un impatto significativo sulle prestazioni delle applicazioni all'interno della macchina virtuale.
  • Il parametro LA viene calcolato in modo errato. Più precisamente, in ogni momento specifico viene calcolato correttamente, ma se calcolato la media su un minuto risulta essere sottostimato. Ad esempio, se una macchina virtuale per terzo dell'hypervisor consuma tutti i suoi processori per esattamente mezzo minuto, il LA al minuto sull'hypervisor sarà 0,15; quattro di queste macchine virtuali che funzionano simultaneamente daranno 0,6. E il fatto che per mezzo minuto su ciascuno di essi si sia verificato un furto selvaggio al 25% secondo l'indicatore LA non può più essere tirato fuori.
  • Ancora una volta, a causa del programmatore che ha deciso che qualcuno stava mangiando troppo e ha lasciato che qualcuno aspettasse. Nel frattempo, cambierò il contesto, gestirò le interruzioni e mi occuperò di altre cose importanti del sistema. Di conseguenza, alcune macchine virtuali non riscontrano alcun problema, mentre altre subiscono un grave degrado delle prestazioni.

4. Altre distorsioni

Esistono un milione di ragioni in più per distorcere il giusto rendimento del tempo del processore su una macchina virtuale. Ad esempio, l'hyperthreading e la NUMA introducono difficoltà nei calcoli. Confondono completamente la scelta del kernel per l'esecuzione del processo, perché lo scheduler utilizza coefficienti - pesi, che rendono il calcolo ancora più difficile quando si cambia contesto.

Ci sono distorsioni dovute a tecnologie come il turbo boost o, al contrario, la modalità di risparmio energetico, che, nel calcolo dell'utilizzo, possono aumentare o diminuire artificialmente la frequenza o addirittura l'intervallo di tempo sul server. L'abilitazione del turbo boost riduce le prestazioni di un thread del processore a causa dell'aumento delle prestazioni di un altro. In questo momento, le informazioni sulla frequenza attuale del processore non vengono trasmesse alla macchina virtuale e ritiene che qualcuno le stia rubando tempo (ad esempio, ha richiesto 2 GHz, ma ne ha ricevuti la metà).

In generale, le ragioni della distorsione possono essere molte. Potresti trovare qualcos'altro su un particolare sistema. È meglio iniziare con i libri a cui ho fornito i collegamenti sopra e recuperare le statistiche dall'hypervisor utilizzando utilità come perf, sysdig, systemtap, di cui decine di.

5. risultati

  1. Una certa quantità di furto può verificarsi a causa della paravirtualizzazione e può essere considerata normale. Scrivono su Internet che questo valore può essere del 5-10%. Dipende dalle applicazioni all'interno della macchina virtuale e dal carico che esercita sui suoi dispositivi fisici. Qui è importante prestare attenzione a come si sentono le applicazioni all'interno delle macchine virtuali.
  2. Il rapporto tra il carico sull'hypervisor e il furto all'interno della macchina virtuale non è sempre chiaramente correlato; entrambe le stime del furto possono essere errate in situazioni specifiche con carichi diversi.
  3. Lo scheduler ha un atteggiamento negativo nei confronti dei processi che richiedono molto. Cerca di dare meno a chi chiede di più. Le grandi macchine virtuali sono malvagie.
  4. Un piccolo furto può essere la norma anche senza paravirtualizzazione (tenendo conto del carico all'interno della macchina virtuale, delle caratteristiche del carico dei vicini, della distribuzione del carico tra i thread e di altri fattori).
  5. Se vuoi capire il furto in un sistema specifico, devi esplorare varie opzioni, raccogliere parametri, analizzarli attentamente e pensare a come distribuire uniformemente il carico. Sono possibili deviazioni da qualsiasi caso, che devono essere confermate sperimentalmente o esaminate nel debugger del kernel.

Fonte: habr.com

Aggiungi un commento