Post Mortem sull'indisponibilità di Quay.io

Nota di traduzione.: all'inizio di agosto Red Hat ha pubblicamente parlato della risoluzione dei problemi di disponibilità che erano emersi nei mesi precedenti per gli utenti del suo servizio Quay.io (alla base vi è un registro per le immagini dei container, ereditato dall'azienda con l'acquisto di CoreOS). Indipendentemente dal vostro interesse per questo servizio, il percorso intrapreso dagli ingegneri SRE dell'azienda per diagnosticare e risolvere le cause dell'incidente è istruttivo.

Post Mortem sull'indisponibilità di Quay.io

Il 19 maggio, presto al mattino (ora estiva dell'America del Nord, EDT), il servizio quay.io è andato giù. L'incidente ha colpito sia i consumatori di quay.io che i progetti Open Source che utilizzano quay.io come piattaforma per la costruzione e la distribuzione del software. Red Hat tiene molto alla fiducia di entrambi.

Il team di ingegneri SRE ha subito iniziato a lavorare per stabilizzare il servizio Quay il prima possibile. Tuttavia, mentre stavano facendo ciò, i clienti hanno perso la possibilità di caricare nuove immagini e solo occasionalmente sono riusciti a scaricare quelle esistenti. Per qualche motivo sconosciuto, il database di quay.io si bloccava dopo la scalabilità del servizio a piena capacità.

«Cosa è cambiato?» — è la prima domanda che si tende a porre in questi casi. Abbiamo notato che poco prima del problema, il cluster OpenShift Dedicated (su cui opera quay.io) ha iniziato ad aggiornarsi alla versione 4.3.19. Poiché quay.io funziona su Red Hat OpenShift Dedicated (OSD), gli aggiornamenti regolari erano operazioni consuete e non avevano mai portato a problemi. Inoltre, negli ultimi sei mesi avevamo aggiornato più volte i cluster Quay senza alcuna interruzione del servizio.

Mentre cercavamo di ripristinare il servizio, altri ingegneri hanno iniziato a preparare un nuovo cluster OSD con la versione precedente del software, per poter intervenire rapidamente in caso di necessità.

Analisi delle cause

Il principale sintomo del guasto era un'ondata di decine di migliaia di connessioni al database, che ha reso l'istanza MySQL praticamente non operativa. Di conseguenza, era difficile diagnosticare il problema. Abbiamo imposto un limite massimo sul numero di connessioni dai client, per aiutare il team SRE a valutare la questione. Non abbiamo notato alcun traffico insolito verso il database: in realtà, la maggior parte delle richieste erano di lettura, mentre solo poche erano di scrittura.

Abbiamo cercato di identificare un modello nel traffico del database che potesse aver causato questa valanga. Tuttavia, non siamo riusciti a trovare alcuna regolarità nei log. In attesa della pronta disponibilità del nuovo cluster con OSD 4.3.18, abbiamo continuato a tentare di avviare i pod di quay.io. Ogni volta che il cluster raggiungeva la piena capacità, il database si bloccava. Questo significava che era necessario riavviare l'istanza RDS oltre a tutti i pod di quay.io.

Entro sera, abbiamo stabilizzato il servizio in modalità di sola lettura e disattivato il massimo delle funzionalità non essenziali (ad esempio, la raccolta dei rifiuti nello spazio dei nomi), per ridurre il carico sul database. I blocchi si erano fermati, ma la causa non era stata ancora trovata. Il nuovo cluster OSD era pronto, e abbiamo trasferito il servizio, collegato il traffico e continuato il monitoraggio.

Quay.io funzionava stabilmente sul nuovo cluster OSD, quindi siamo tornati ai log del database, ma non siamo riusciti a rilevare alcuna correlazione che spiegasse i blocchi. Gli ingegneri di OpenShift lavoravano insieme a noi, cercando di capire se le modifiche in Red Hat OpenShift 4.3.19 potessero aver causato problemi con Quay. Tuttavia, non è emerso nulla, e non siamo riusciti a riprodurre il problema in laboratorio.

Il secondo guasto

il 28 maggio, poco prima di mezzogiorno EDT, quay.io è crollato di nuovo con gli stessi sintomi: il funzionamento del database era bloccato. Ancora una volta abbiamo messo in campo tutte le nostre forze per l'inchiesta. Prima di tutto, era necessario ristabilire il servizio. Tuttavia, questa volta il riavvio di RDS e il riavvio dei pod di quay.io non hanno portato a nulla: un'altra valanga di connessioni ha travolto il database. Ma perché?

Quay è scritto in Python, e ogni pod funziona come un singolo contenitore monolitico. In un ambiente di esecuzione del contenitore, vengono eseguite molte attività parallele contemporaneamente. Utilizziamo la libreria gevent a gunicorn per gestire le richieste web. Quando Quay riceve una richiesta (tramite la nostra API o tramite l'API di Docker), viene assegnato un worker gevent. Di solito, questo worker deve collegarsi al database. Dopo il primo guasto, abbiamo scoperto che i worker gevent si collegavano al database utilizzando le impostazioni predefinite.

Considerando il numero significativo di pod di Quay e le migliaia di richieste in arrivo al secondo, un alto numero di connessioni al database poteva teoricamente sovraccaricare l'istanza di MySQL. Grazie al monitoraggio, si sapeva che Quay gestiva in media 5.000 richieste al secondo. Circa lo stesso era il numero di connessioni al database. 5.000 connessioni rientravano comodamente nelle capacità della nostra istanza RDS (cosa che non si può dire per decine di migliaia). Per qualche motivo si verificavano picchi inaspettati nel numero di connessioni, tuttavia non notavamo alcuna correlazione con le richieste in arrivo.

Questa volta abbiamo deciso fermamente di trovare e risolvere la fonte del problema, anziché limitarci a riavviare. Nella base di codice di Quay sono state apportate modifiche che limitano il numero di connessioni al DB per ogni worker gevent. Questo numero è diventato un parametro nella configurazione: è stato possibile modificarlo "al volo", senza ricompilare una nuova immagine del container. Per sapere quanti collegamenti potevano realmente essere gestiti, sono stati condotti diversi test con l'ambiente di staging, in cui venivano impostati valori diversi per osservare come ciò influenzasse gli scenari di stress test. Alla fine, è emerso che Quay inizia a restituire errori 502 quando il numero di connessioni supera i 10.000.

Abbiamo immediatamente distribuito questa nuova versione in produzione e abbiamo iniziato a monitorare il grafico delle connessioni al database. In passato, il database si bloccava dopo circa 20 minuti. Dopo 30 minuti senza problemi, avevamo speranza e dopo un'ora — certezza. Abbiamo ripristinato il traffico di scrittura sul sito e abbiamo iniziato l'analisi post-mortem.

Siamo riusciti a eludere il problema che portava al blocco, ma non abbiamo identificato le sue vere cause. È stato confermato che non era correlato a cambiamenti in OpenShift 4.3.19, poiché lo stesso era accaduto anche nella versione 4.3.18, che prima funzionava con Quay senza alcun problema.

Nel cluster c'era chiaramente altro da scoprire.

Un'analisi dettagliata

Quay.io ha utilizzato le impostazioni predefinite per la connessione al database per sei anni senza alcun problema. Cosa è cambiato? È chiaro che nel frattempo il traffico su quay.io è costantemente aumentato. Nel nostro caso, sembrava che fosse stata raggiunta una certa soglia che ha attivato un'ondata di connessioni. Abbiamo continuato a esaminare i log del database dopo il secondo guasto, ma non abbiamo trovato alcun schema o connessione evidente.

Nel frattempo, il team SRE si è occupato di miglioramenti nella visibilità delle richieste su Quay e della salute generale del servizio. Sono state implementate nuove metriche e dashboard, mostrando quali parti di Quay sono più richieste dai clienti.

Quay.io ha funzionato normalmente fino al 9 giugno. Al mattino (in EDT) siamo stati ancora testimoni di un significativo aumento del numero di connessioni al database. Questa volta non ci sono stati downtime, poiché un nuovo parametro limitava il loro numero e impediva di superare la capacità di MySQL. Tuttavia, per circa mezz'ora molti utenti hanno riscontrato prestazioni lente su quay.io. Abbiamo rapidamente raccolto tutti i dati disponibili, sfruttando gli strumenti di monitoraggio aggiunti. Improvvisamente si è manifestato uno schema.

Prima del picco delle connessioni, un gran numero di richieste è pervenuto all'App Registry API. L'App Registry è una funzione poco conosciuta di quay.io. Consente di memorizzare elementi come i chart Helm e i contenitori con metadati ricchi. La maggior parte degli utenti di quay.io non utilizza questa funzione, ma è ampiamente utilizzata da Red Hat OpenShift. OperatorHub all'interno di OpenShift memorizza tutti gli operatori nell'App Registry. Questi operatori costituiscono la base per l'ecosistema delle workload di OpenShift e il modello operativo (nell'ambito delle operazioni del "secondo giorno", Day 2) orientato ai partner.

Ogni cluster OpenShift 4 utilizza gli operatori incorporati in OperatorHub per pubblicare un catalogo di operatori disponibili per l'installazione e per fornire aggiornamenti per quelli già installati. Con l'aumento della popolarità di OpenShift 4, è aumentato anche il numero di cluster in tutto il mondo. Ognuno di questi cluster carica il contenuto degli operatori per avviare il proprio OperatorHub incorporato, utilizzando l'App Registry all'interno di quay.io come backend. Nella ricerca della fonte del problema, abbiamo trascurato il fatto che, con la crescente popolarità di OpenShift, aumentava anche il carico su una delle funzioni raramente utilizzate di quay.io..

Abbiamo effettuato un'analisi del traffico delle richieste dell'App Registry e abbiamo esaminato il codice del registro. Sono emersi immediatamente dei difetti che causavano una formazione non ottimale delle richieste al database. Con un carico ridotto non causavano alcun problema, ma con l'aumento diventavano fonte di problemi. L'App Registry aveva due endpoint problematici, che rispondevano male all'aumento del carico: il primo restituiva l'elenco di tutti i pacchetti nel repository, il secondo restituiva tutti i blob per un pacchetto.

Rimozione delle cause

Per tutta la settimana successiva ci siamo dedicati all'ottimizzazione del codice stesso dell'App Registry e del suo ambiente. Sono state rielaborate richieste SQL visibilmente inefficienti, eliminate chiamate non necessarie al comando tar (veniva eseguita ad ogni estrazione dei blob), aggiunto caching ovunque fosse possibile. Successivamente, è stato effettuato un ampio testing delle prestazioni e confrontata la velocità di funzionamento dell'App Registry prima e dopo le modifiche.

Le richieste API che prima richiedevano fino a trenta secondi ora venivano eseguite in millisecondi.La settimana successiva abbiamo implementato le modifiche in produzione e da allora quay.io funziona stabilmente. In quel periodo si sono verificati alcuni picchi di traffico sul'endpoint dell'App Registry, ma i miglioramenti realizzati hanno impedito interruzioni nel funzionamento del database.

Cosa abbiamo imparato?

È chiaro che ogni servizio cerca di evitare i downtime. Nel nostro caso, crediamo che i recenti malfunzionamenti abbiano contribuito a rendere quay.io migliore. Abbiamo appreso alcune lezioni fondamentali di cui vogliamo condividere:

  1. I dati su chi e come utilizza il tuo servizio non sono mai superflui.Poiché Quay "funzionava semplicemente", non abbiamo mai sentito la necessità di spendere tempo per ottimizzare il traffico e gestire il carico. Tutto ciò ha creato una falsa sensazione di sicurezza che il servizio potesse scalare all'infinito.
  2. Quando un servizio si interrompe, il ripristino del suo funzionamento è la massima priorità.. Poiché Quay continuava a soffrire di un database bloccato durante il primo guasto, le nostre procedure standard non hanno avuto l'effetto previsto e non siamo riusciti a ripristinare il servizio con il loro aiuto. Questo ha portato a una situazione in cui è stato necessario perdere tempo ad analizzare e raccogliere dati nella speranza di trovare la causa principale, piuttosto che concentrare tutti gli sforzi sul ripristino della funzionalità.
  3. Valuta l'impatto di ciascuna delle funzioni del servizio. I clienti raramente utilizzavano App Registry, quindi non era una priorità per il nostro team. Quando alcune funzioni del prodotto vengono utilizzate poco, i loro bug ''emergono'' raramente e gli sviluppatori smettono di seguire il codice. È facile cadere nell'illusione che sia normale — finché improvvisamente quella funzione non si ritrova al centro di un incidente su larga scala.

Cosa succede dopo?

Il lavoro per garantire la stabilità del servizio non si ferma mai e continuiamo a migliorarlo. I volumi di traffico su quay.io continuano a crescere e siamo consapevoli di dover fare tutto il possibile per rispettare la fiducia dei clienti. Pertanto, attualmente stiamo lavorando sui seguenti obiettivi:

  1. Distribuzione di repliche di database solo per la lettura, per aiutare il servizio a gestire il traffico adeguato in caso di problemi con l'istanza principale di RDS.
  2. Aggiornamento dell'istanza di RDS. L'attuale versione di per sé non è problematica. Piuttosto, vogliamo semplicemente eliminare una falsa pista (seguita durante il guasto); mantenere il software aggiornato aiuterà a rimuovere un ulteriore fattore in caso di futuri downtime.
  3. Caching aggiuntivo in tutto il cluster. Continuiamo a cercare aree in cui il caching possa contribuire a ridurre il carico sul database.
  4. Aggiunta di un firewall per applicazioni web (WAF), per vedere chi si connette a quay.io e perché.
  5. A partire dalla prossima versione, i cluster Red Hat OpenShift abbandoneranno App Registry a favore dei cataloghi degli operatori (Operator Catalogs), basati su immagini dei container disponibili su quay.io.
  6. Una sostituzione a lungo termine di App Registry potrebbe essere il supporto per le specifiche degli artefatti dell'Open Container Initiative (OCI). Attualmente è implementato come funzionalità nativa di Quay e sarà disponibile per gli utenti quando la specifica sarà definitivamente concordata.

Tutto quanto sopra fa parte degli investimenti continui di Red Hat in quay.io mentre passiamo da un piccolo team "in stile startup" a una piattaforma matura gestita da SRE. Sappiamo che molti dei nostri clienti si affidano a quay.io nel loro lavoro quotidiano (compresa Red Hat!) e ci impegniamo a essere il più trasparenti possibile riguardo ai recenti interventi e agli sforzi continui per migliorarci.

P.S. dal traduttore

Leggi anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster