Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU

Nel 2016 noi di Buffer passato a Kubernetes, e ora circa 60 nodi (su AWS) e 1500 container stanno lavorando sul nostro cluster k8s gestito da kop. Tuttavia, siamo passati ai microservizi attraverso tentativi ed errori e, anche dopo diversi anni di lavoro con K8, dobbiamo ancora affrontare nuovi problemi. In questo post parleremo di limitazioni del processore: perché pensavamo che fossero buone pratiche e perché alla fine non lo sono state.

Limitazioni e throttling del processore

Come molti altri utenti Kubernetes, Google consiglia vivamente di impostare limiti di CPU. Senza tale impostazione, i contenitori in un nodo possono assorbire tutta la potenza del processore, il che a sua volta causa importanti processi Kubernetes (ad esempio kubelet) smetterà di rispondere alle richieste. Pertanto, impostare i limiti della CPU è un buon modo per proteggere i tuoi nodi.

I limiti del processore impostano un contenitore sul tempo massimo della CPU che può utilizzare per un periodo specifico (il valore predefinito è 100 ms) e il contenitore non supererà mai questo limite. In Kubernetes per strozzatura contenitore ed evitare che superi il limite, viene utilizzato uno strumento speciale Quota CFS, ma questi limiti artificiali della CPU finiscono per compromettere le prestazioni e aumentare il tempo di risposta dei contenitori.

Cosa può succedere se non impostiamo limiti per il processore?

Sfortunatamente, noi stessi abbiamo dovuto affrontare questo problema. Ogni nodo ha un processo responsabile della gestione dei contenitori kubelet, e ha smesso di rispondere alle richieste. Il nodo, quando ciò accadrà, entrerà nello stato NotReadye i contenitori da esso verranno reindirizzati altrove e creeranno gli stessi problemi sui nuovi nodi. Non è uno scenario ideale, per usare un eufemismo.

Manifestazione del problema di strozzamento e risposta

La metrica chiave per il monitoraggio dei container è trottling, mostra quante volte il tuo contenitore è stato limitato. Abbiamo notato con interesse la presenza di throttling in alcuni contenitori, indipendentemente dal fatto che il carico del processore fosse estremo o meno. Ad esempio, diamo un'occhiata a una delle nostre API principali:

Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU

Come puoi vedere di seguito, abbiamo impostato il limite a 800m (0.8 o 80% core) e valori di picco al massimo raggiungibili 200m (20% nucleo). Sembrerebbe che prima di limitare il servizio abbiamo ancora molta potenza del processore, tuttavia...

Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU
Potresti aver notato che anche quando il carico del processore è al di sotto dei limiti specificati - significativamente al di sotto - si verifica ancora del throttling.

Di fronte a ciò, abbiamo presto scoperto diverse risorse (problema su github, presentazione su zadano, pubblica su omio) sul calo delle prestazioni e dei tempi di risposta dei servizi dovuto al throttling.

Perché vediamo throttling con un carico basso della CPU? La versione breve è: "c'è un bug nel kernel Linux che causa un'inutile limitazione dei contenitori con limiti di processore specificati". Se sei interessato alla natura del problema, puoi leggere la presentazione (video и testo opzioni) di Dave Chiluk.

Rimozione delle limitazioni della CPU (con estrema cautela)

Dopo lunghe discussioni, abbiamo deciso di rimuovere le restrizioni sul processore da tutti i servizi che direttamente o indirettamente influivano sulle funzionalità critiche per i nostri utenti.

La decisione non è stata facile perché teniamo molto alla stabilità del nostro cluster. In passato abbiamo già sperimentato l'instabilità del nostro cluster, e poi i servizi consumavano troppe risorse e rallentavano il lavoro dell'intero nodo. Ora tutto era un po’ diverso: avevamo una chiara comprensione di ciò che ci aspettavamo dai nostri cluster, nonché una buona strategia per implementare i cambiamenti pianificati.

Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU
Corrispondenza commerciale su una questione urgente.

Come proteggere i tuoi nodi quando le restrizioni vengono rimosse?

Isolamento dei servizi “illimitati”:

In passato, abbiamo già visto alcuni nodi entrare in uno stato notReady, principalmente a causa dei servizi che consumavano troppe risorse.

Abbiamo deciso di collocare tali servizi in nodi separati (“etichettati”) in modo che non interferiscano con i servizi “correlati”. Di conseguenza, contrassegnando alcuni nodi e aggiungendo il parametro di tolleranza ai servizi “non correlati”, abbiamo ottenuto un maggiore controllo sul cluster ed è diventato più semplice per noi identificare i problemi con i nodi. Per eseguire tu stesso processi simili, puoi familiarizzare con documentazione.

Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU

Assegnazione di un processore corretto e di una richiesta di memoria:

La nostra paura più grande era che il processo consumasse troppe risorse e il nodo smettesse di rispondere alle richieste. Dato che ora (grazie a Datadog) possiamo monitorare chiaramente tutti i servizi del nostro cluster, ho analizzato diversi mesi di funzionamento di quelli che intendevamo designare come “non correlati”. Ho semplicemente impostato l'utilizzo massimo della CPU con un margine del 20% e quindi allocato lo spazio nel nodo nel caso in cui k8s tenti di assegnare altri servizi al nodo.

Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU

Come puoi vedere nel grafico, è stato raggiunto il carico massimo sul processore 242m Core della CPU (0.242 core del processore). Per una richiesta al processore è sufficiente prendere un numero leggermente maggiore di questo valore. Tieni presente che poiché i servizi sono incentrati sull'utente, i valori di picco di carico coincidono con il traffico.

Fai lo stesso con l'utilizzo della memoria e le query e voilà: è tutto pronto! Per maggiore sicurezza, puoi aggiungere la scalabilità automatica orizzontale dei pod. Pertanto, ogni volta che il carico delle risorse è elevato, la scalabilità automatica creerà nuovi pod e Kubernetes li distribuirà ai nodi con spazio libero. Nel caso in cui non ci sia più spazio nel cluster stesso, puoi impostare un avviso o configurare l'aggiunta di nuovi nodi tramite la loro scalabilità automatica.

Tra gli aspetti negativi, vale la pena notare che abbiamo perso in "densità del contenitore", cioè. numero di contenitori in esecuzione su un nodo. Potremmo anche avere molti "rilassamenti" a bassa densità di traffico, e c'è anche la possibilità che tu raggiunga un carico elevato del processore, ma i nodi di scalabilità automatica dovrebbero aiutare con quest'ultimo.

Giudizio

Sono lieto di pubblicare questi eccellenti risultati degli esperimenti delle ultime settimane; abbiamo già riscontrato miglioramenti significativi nella risposta in tutti i servizi modificati:

Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU

Abbiamo ottenuto i migliori risultati sulla nostra home page (buffer.com), lì il servizio ha subito un'accelerazione ventidue volte!

Kubernetes: velocizza i tuoi servizi rimuovendo i limiti della CPU

Il bug del kernel Linux è stato corretto?

Sì, Il bug è già stato corretto e la correzione è stata aggiunta al kernel distribuzioni versione 4.19 e successive.

Tuttavia, dopo aver letto Problemi di Kubernetes su Github per il 2020 settembre XNUMX incontriamo ancora menzioni di alcuni progetti Linux con un bug simile. Credo che alcune distribuzioni Linux abbiano ancora questo bug e stiano lavorando per risolverlo.

Se la versione della tua distribuzione è inferiore alla 4.19, ti consiglio di aggiornare all'ultima, ma in ogni caso dovresti provare a rimuovere le restrizioni del processore e vedere se il throttling persiste. Di seguito puoi vedere un elenco parziale dei servizi di gestione Kubernetes e delle distribuzioni Linux:

  • Debian: correzione integrata nell'ultima versione della distribuzione, Buster, e sembra abbastanza fresco (Agosto 2020 anni). Anche alcune versioni precedenti potrebbero essere corrette.
  • Ubuntu: correzione integrata nell'ultima versione Ubuntu Focale Fossa 20.04
  • EKS ha ancora trovato una soluzione a dicembre 2019 dell'anno. Se la tua versione è precedente a questa, dovresti aggiornare l'AMI.
  • kops: Da giugno 2020 у kops 1.18+ L'immagine host principale sarà Ubuntu 20.04. Se la tua versione di kops è precedente, potresti dover attendere una correzione. Noi stessi stiamo aspettando ora.
  • GKE (Google Cloud): correzione integrata nel gennaio 2020, tuttavia ci sono problemi con il throttling sono ancora osservati.

Cosa fare se la correzione risolve il problema di limitazione?

Non sono sicuro che il problema sia completamente risolto. Quando arriveremo alla versione del kernel con la correzione, testerò il cluster e aggiornerò il post. Se qualcuno ha già aggiornato, sarei interessato a leggere i risultati.

conclusione

  • Se lavori con contenitori Docker sotto Linux (non importa Kubernetes, Mesos, Swarm o altri), i tuoi contenitori potrebbero perdere prestazioni a causa della limitazione;
  • Prova ad aggiornare all'ultima versione della tua distribuzione nella speranza che il bug sia già stato corretto;
  • Rimuovere i limiti del processore risolverà il problema, ma si tratta di una tecnica pericolosa che va utilizzata con estrema cautela (è meglio aggiornare prima il kernel e confrontare i risultati);
  • Se hai rimosso i limiti della CPU, monitora attentamente l'utilizzo della CPU e della memoria e assicurati che le risorse della CPU superino il tuo consumo;
  • Un'opzione sicura sarebbe quella di scalare automaticamente i pod per creare nuovi pod in caso di carico hardware elevato, in modo che Kubernetes li assegni a nodi liberi.

Spero che questo post ti aiuti a migliorare le prestazioni dei tuoi sistemi di contenitori.

PS Qui l'autore corrisponde con lettori e commentatori (in inglese).


Fonte: habr.com

Aggiungi un commento