Post Mortem sull'indisponibilità di Quay.io

Nota. trad.: all'inizio di agosto, Red Hat ha parlato pubblicamente della risoluzione dei problemi di accessibilità che gli utenti del suo servizio avevano riscontrato nei mesi precedenti quay.io (si basa su un registro delle immagini dei contenitori, che l'azienda ha ricevuto insieme all'acquisto di CoreOS). Indipendentemente dal tuo interesse per questo servizio in quanto tale, il percorso intrapreso dagli ingegneri SRE dell’azienda per diagnosticare ed eliminare le cause dell’incidente è istruttivo.

Post Mortem sull'indisponibilità di Quay.io

Il 19 maggio, la mattina presto (Eastern Daylight Time, EDT), il servizio quay.io si è bloccato. L'incidente ha colpito sia i consumatori di quay.io che i progetti Open Source che utilizzano quay.io come piattaforma per la creazione e la distribuzione di software. Red Hat apprezza la fiducia di entrambi.

Una squadra di ingegneri della SRE si è immediatamente impegnata e ha cercato di stabilizzare il servizio in banchina nel più breve tempo possibile. Tuttavia, mentre lo facevano, i clienti perdevano la capacità di inviare nuove immagini e solo occasionalmente erano in grado di estrarre quelle esistenti. Per qualche motivo sconosciuto, il database quay.io è stato bloccato dopo aver portato il servizio alla piena capacità.

«Cosa è cambiato?" - questa è la prima domanda che di solito viene posta in questi casi. Abbiamo notato che poco prima del problema, il cluster OpenShift Dedicated (che esegue quay.io) ha iniziato ad aggiornarsi alla versione 4.3.19. Poiché quay.io viene eseguito su Red Hat OpenShift Dedicated (OSD), gli aggiornamenti regolari erano di routine e non hanno mai causato problemi. Inoltre, negli ultimi sei mesi, abbiamo 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, in modo che, se fosse successo qualcosa, avrebbero potuto distribuirvi tutto.

Analisi delle cause profonde

Il sintomo principale del fallimento è stata una valanga di decine di migliaia di connessioni al database, che hanno reso l’istanza MySQL di fatto inutilizzabile. Ciò ha reso difficile la diagnosi del problema. Abbiamo impostato un limite al numero massimo di connessioni da parte dei client per aiutare il team SRE a valutare il problema. Non abbiamo notato alcun traffico insolito verso il database: infatti, la maggior parte delle richieste sono state lette e solo poche scritte.

Abbiamo anche cercato di identificare uno schema nel traffico del database che potrebbe causare questa valanga. Tuttavia, non siamo riusciti a trovare alcun modello nei registri. In attesa che il nuovo cluster con OSD 4.3.18 fosse pronto, abbiamo continuato a provare a lanciare i pod quay.io. Ogni volta che il cluster raggiungeva la piena capacità, il database si bloccava. Ciò significava che era necessario riavviare l'istanza RDS oltre a tutti i pod quay.io.

Entro la sera, abbiamo stabilizzato il servizio in modalità di sola lettura e disabilitato quante più funzioni non essenziali possibili (ad esempio, la garbage collection dello spazio dei nomi) per ridurre il carico sul database. I geli sono cessati ma il motivo non è mai stato trovato. Il nuovo cluster OSD era pronto e abbiamo migrato il servizio, collegato il traffico e continuato il monitoraggio.

Quay.io ha funzionato stabilmente sul nuovo cluster OSD, quindi siamo tornati ai log del database, ma non siamo riusciti a trovare una correlazione che spiegasse i blocchi. Gli ingegneri di OpenShift hanno lavorato con noi per capire se i cambiamenti in Red Hat OpenShift 4.3.19 potessero causare problemi con Quay. Tuttavia, non è stato trovato nulla e Non è stato possibile riprodurre il problema in condizioni di laboratorio.

Secondo fallimento

Il 28 maggio, poco prima di mezzogiorno EDT, quay.io si è bloccato di nuovo con lo stesso sintomo: il database era bloccato. E ancora una volta abbiamo dedicato tutto il nostro impegno alle indagini. Innanzitutto era necessario ripristinare il servizio. Tuttavia questa volta il riavvio di RDS e il riavvio dei pod quay.io non hanno fatto nulla: un'altra valanga di collegamenti ha travolto la base. Ma perché?

Quay è scritto in Python e ogni pod funziona come un singolo contenitore monolitico. Il runtime del contenitore esegue molte attività parallele contemporaneamente. Usiamo la biblioteca gevent sotto gunicorn per elaborare le richieste web. Quando una richiesta arriva a Quay (tramite la nostra API o tramite l'API di Docker), le viene assegnato un lavoratore gevent. In genere questo lavoratore dovrebbe contattare il database. Dopo il primo errore, abbiamo scoperto che i lavoratori gevent si connettevano al database utilizzando le impostazioni predefinite.

Dato il numero significativo di pod Quay e le migliaia di richieste in entrata al secondo, un gran numero di connessioni al database potrebbe teoricamente sopraffare l'istanza MySQL. Grazie al monitoraggio si è saputo che Quay elabora in media 5mila richieste al secondo. Il numero di connessioni al database era approssimativamente lo stesso. 5mila connessioni rientravano ampiamente nelle capacità della nostra istanza RDS (che non si può dire di decine di migliaia). Per qualche motivo si sono verificati picchi inaspettati nel numero di connessioni, tuttavia, non abbiamo notato alcuna correlazione con le richieste in arrivo.

Questa volta eravamo determinati a trovare ed eliminare la fonte del problema e non limitarci al riavvio. Al codice base di Quay sono state apportate modifiche per limitare il numero di connessioni al database per ciascun lavoratore gevent. Questo numero è diventato un parametro nella configurazione: è diventato possibile modificarlo al volo senza creare una nuova immagine del contenitore. Per scoprire quante connessioni potrebbero essere realisticamente gestite, abbiamo eseguito diversi test in un ambiente di staging, impostando valori diversi per vedere come questo avrebbe influenzato gli scenari di test di carico. Di conseguenza, si è scoperto che Quay inizia a lanciare errori 502 quando il numero di connessioni supera i 10mila.

Abbiamo immediatamente distribuito questa nuova versione in produzione e abbiamo iniziato a monitorare la pianificazione della connessione al database. In passato la base veniva bloccata dopo circa 20 minuti. Dopo 30 minuti senza problemi avevamo speranza e un'ora dopo avevamo fiducia. Abbiamo ripristinato il traffico sul sito e iniziato l'analisi post-mortem.

Essendo riuscito ad aggirare il problema che portava al blocco, non abbiamo scoperto le sue vere ragioni. È stato confermato che non è correlato ad alcuna modifica in OpenShift 4.3.19, poiché la stessa cosa è accaduta nella versione 4.3.18, che in precedenza funzionava con Quay senza problemi.

C'era chiaramente qualcos'altro in agguato nel cluster.

Studio dettagliato

Quay.io ha utilizzato le impostazioni predefinite per connettersi al database per sei anni senza problemi. Cosa è cambiato? È chiaro che in tutto questo tempo il traffico su quay.io è cresciuto costantemente. Nel nostro caso sembrava che fosse stato raggiunto un valore soglia che ha fatto da innesco ad una valanga di collegamenti. Abbiamo continuato a studiare i log del database dopo il secondo errore, ma non abbiamo trovato alcun modello o relazione evidente.

Nel frattempo, il team SRE ha lavorato per migliorare l'osservabilità delle richieste di Quay e l'integrità generale del servizio. Sono state implementate nuove metriche e dashboard, mostrando quali parti della banchina sono più richieste dai clienti.

Quay.io ha funzionato bene fino al 9 giugno. Questa mattina (EDT) abbiamo riscontrato nuovamente un aumento significativo nel numero di connessioni al database. Questa volta non ci sono stati tempi di inattività, poiché il nuovo parametro ne limitava il numero e non consentiva loro di superare il throughput di MySQL. Tuttavia, per circa mezz’ora, molti utenti hanno notato un rallentamento delle prestazioni di quay.io. Abbiamo raccolto rapidamente tutti i dati possibili utilizzando gli strumenti di monitoraggio aggiunti. All'improvviso è emerso uno schema.

Poco prima dell'impennata delle connessioni, sono state effettuate numerose richieste all'API del registro delle app. Il registro delle app è una funzionalità poco conosciuta di quay.io. Ti consente di archiviare elementi come grafici Helm e contenitori con metadati avanzati. La maggior parte degli utenti quay.io non utilizza questa funzionalità, ma Red Hat OpenShift la utilizza attivamente. OperatorHub come parte di OpenShift memorizza tutti gli operatori nel registro delle app. Questi operatori costituiscono la base per l'ecosistema del carico di lavoro OpenShift e il modello operativo incentrato sui partner (operazioni del secondo giorno).

Ogni cluster OpenShift 4 utilizza gli operatori dell'OperatorHub integrato per pubblicare un catalogo di operatori disponibili per l'installazione e fornire aggiornamenti a quelli già installati. Con la crescente popolarità di OpenShift 4, è aumentato anche il numero di cluster presenti in tutto il mondo. Ciascuno di questi cluster scarica il contenuto dell'operatore per eseguire OperatorHub integrato, utilizzando il registro delle app all'interno di quay.io come backend. Nella nostra ricerca dell’origine del problema, non ci siamo accorti del fatto che, man mano che OpenShift cresceva in popolarità, aumentava anche il carico su una delle funzioni quay.io raramente utilizzate..

Abbiamo effettuato alcune analisi del traffico delle richieste del registro delle app e dato un'occhiata al codice del registro. Immediatamente sono emerse delle carenze, a causa delle quali le query al database non sono state formate in modo ottimale. Quando il carico era basso non causavano alcun problema, ma quando il carico aumentava diventavano fonte di problemi. Si è scoperto che il registro delle app aveva due endpoint problematici che non rispondevano bene all'aumento del carico: il primo forniva un elenco di tutti i pacchetti nel repository, il secondo restituiva tutti i BLOB del pacchetto.

Eliminazione delle cause

Nella settimana successiva abbiamo dedicato all'ottimizzazione del codice del registro delle app stesso e del suo ambiente. Le query SQL chiaramente inefficaci sono state rielaborate e le chiamate di comandi non necessarie sono state eliminate tar (veniva eseguito ogni volta che venivano recuperati i BLOB), è stata aggiunta la memorizzazione nella cache ove possibile. Abbiamo quindi condotto test approfonditi sulle prestazioni e confrontato la velocità del registro delle app prima e dopo le modifiche.

Le richieste API che in precedenza richiedevano fino a mezzo minuto vengono ora completate in millisecondi. La settimana successiva abbiamo implementato le modifiche alla produzione e da allora quay.io ha funzionato stabilmente. Durante questo periodo, si sono verificati diversi picchi netti nel traffico sull'endpoint del registro delle app, ma i miglioramenti apportati hanno impedito interruzioni del database.

Cosa abbiamo imparato?

È chiaro che qualsiasi servizio cerca di evitare tempi di inattività. Nel nostro caso, riteniamo che le recenti interruzioni abbiano contribuito a migliorare quay.io. Abbiamo imparato alcune lezioni chiave che vorremmo condividere:

  1. I dati su chi utilizza il tuo servizio e come non sono mai superflui. Poiché Quay “funzionava e basta”, non abbiamo mai dovuto dedicare tempo all'ottimizzazione del traffico e alla gestione del carico. Tutto ciò creava un falso senso di sicurezza secondo cui il servizio poteva espandersi indefinitamente.
  2. Quando il servizio cade, rimetterlo in funzione è una priorità assoluta.. Poiché Quay continuava a soffrire di un database bloccato durante la prima interruzione, le nostre procedure standard non hanno avuto l'effetto desiderato e non siamo stati in grado di ripristinare il servizio utilizzandole. Ciò ha portato a una situazione in cui è stato necessario dedicare tempo all'analisi e alla raccolta dei dati nella speranza di trovare la causa principale, invece di concentrare tutti gli sforzi sul ripristino della funzionalità.
  3. Valutare l'impatto di ciascuna funzionalità del servizio. I clienti utilizzavano raramente il Registro delle app, quindi non era una priorità per il nostro team. Quando alcune funzionalità del prodotto vengono utilizzate a malapena, i relativi bug compaiono raramente e gli sviluppatori smettono di monitorare il codice. È facile cadere preda dell'idea sbagliata che così dovrebbe essere, finché all'improvviso quella funzione si ritrova al centro di un grave incidente.

Quali sono le prospettive?

Il lavoro per garantire la stabilità del servizio non si ferma mai e lo miglioriamo costantemente. Poiché i volumi di traffico continuano a crescere su quay.io, riconosciamo di avere la responsabilità di fare tutto il possibile per essere all'altezza della fiducia dei nostri clienti. Pertanto, attualmente stiamo lavorando sui seguenti compiti:

  1. Distribuisci repliche di database di sola lettura per aiutare il servizio a gestire il traffico appropriato in caso di problemi con l'istanza RDS primaria.
  2. Aggiornamento di un'istanza RDS. La versione attuale in sé non è il problema. Vogliamo piuttosto semplicemente rimuovere la falsa pista (che abbiamo seguito durante il fallimento); Mantenere aggiornato il software eliminerà un altro fattore in caso di interruzioni future.
  3. Caching aggiuntivo nell'intero cluster. Continuiamo a cercare aree in cui la memorizzazione nella cache può 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 release, i cluster Red Hat OpenShift abbandoneranno il Registro delle app a favore dei cataloghi degli operatori basati sulle immagini dei container disponibili su quay.io.
  6. Una sostituzione a lungo termine del Registro app potrebbe essere il supporto per le specifiche degli artefatti Open Container Initiative (OCI). Attualmente è implementata come funzionalità nativa di Quay e sarà disponibile per gli utenti una volta finalizzate le specifiche stesse.

Tutto quanto sopra fa parte del continuo investimento di Red Hat in quay.io mentre passiamo da un piccolo team "in stile startup" a una piattaforma matura basata su SRE. Sappiamo che molti dei nostri clienti si affidano a quay.io nel loro lavoro quotidiano (inclusa Red Hat!) e cerchiamo di essere il più trasparenti possibile riguardo alle recenti interruzioni e agli sforzi continui per migliorare.

PS da traduttore

Leggi anche sul nostro blog:

Fonte: habr.com

Aggiungi un commento