Roblox torna in servizio

A partire dal 28 ottobre e risolvendosi completamente il 31 ottobre, Roblox ha subito un'interruzione del servizio della durata di 73 ore.¹ Cinquanta milioni di giocatori utilizzano regolarmente Roblox ogni giorno e, per creare l'esperienza che i nostri giocatori si aspettano, la nostra struttura coinvolge centinaia di servizi online interni. Come per qualsiasi servizio su larga scala, di tanto in tanto si verificano interruzioni del servizio, ma la durata prolungata di questa interruzione la rende particolarmente degna di nota. Ci scusiamo sinceramente con la nostra comunità per il periodo di inattività.
Condividiamo questi dettagli tecnici per fornire alla nostra comunità una comprensione della causa principale del problema, di come l'abbiamo affrontato e di cosa stiamo facendo per evitare che problemi simili si verifichino in futuro. Vorremmo ribadire che durante l'incidente non si è verificata alcuna perdita di dati degli utenti né alcun accesso da parte di soggetti non autorizzati alle informazioni.
Il team di ingegneri di Roblox e lo staff tecnico di HashiCorp hanno unito le forze per ripristinare il servizio di Roblox. Desideriamo ringraziare il team di HashiCorp, che ha messo a disposizione risorse incredibili e ha lavorato instancabilmente con noi fino alla risoluzione dei problemi.
Riepilogo dell'interruzione
L'interruzione è stata unica sia per durata che per complessità. Il team ha dovuto affrontare una serie di sfide in sequenza per comprendere la causa principale e ripristinare il servizio.
- L'interruzione è durata 73 ore.
- La causa principale era dovuta a due problemi. L'abilitazione di una funzionalità di streaming relativamente nuova su Consul in presenza di un carico di lettura e scrittura insolitamente elevato ha portato a un'eccessiva contesa e a prestazioni scadenti. Inoltre, le nostre particolari condizioni di carico hanno innescato un problema di prestazioni patologico in BoltDB. Il sistema open source BoltDB viene utilizzato all'interno di Consul per gestire i log di scrittura anticipata per l'elezione del leader e la replica dei dati.
- Un unico cluster Consul che supportava più carichi di lavoro ha esacerbato l’impatto di questi problemi.
- Le difficoltà nel diagnosticare questi due problemi, in gran parte non correlati tra loro e sepolti in profondità nell'implementazione di Consul, sono state in gran parte responsabili del prolungato periodo di inattività.
- I sistemi di monitoraggio critici che avrebbero fornito una migliore visibilità sulla causa dell'interruzione si basavano sui sistemi interessati, come Consul. Questa combinazione ha ostacolato gravemente il processo di triage.
- Abbiamo adottato un approccio ponderato e attento per riportare Roblox da uno stato di interruzione totale prolungata, il che ha richiesto anche un tempo notevole.
- Abbiamo intensificato gli sforzi ingegneristici per migliorare il nostro monitoraggio, rimuovere le dipendenze circolari nel nostro stack di osservabilità e accelerare il nostro processo di avvio.
- Stiamo lavorando per passare a più zone di disponibilità e data center.
- Stiamo risolvendo i problemi in Consul che sono stati la causa principale di questo evento.
Premessa: il nostro ambiente cluster e HashiStack
L'infrastruttura principale di Roblox è in esecuzione nei data center di Roblox. Distribuiamo e gestiamo il nostro hardware, nonché i nostri sistemi di elaborazione, archiviazione e rete su tale hardware. La portata della nostra distribuzione è significativa, con oltre 18.000 server e 170.000 container.
Per gestire migliaia di server in più siti, utilizziamo una suite tecnologica comunemente nota come "HashiStack". Nomad, Consul e Vault sono le tecnologie che utilizziamo per gestire server e servizi in tutto il mondo e che ci consentono di orchestrare i container che supportano i servizi Roblox.
Nomad viene utilizzato per la pianificazione del lavoro. Decide quali container verranno eseguiti su quali nodi e su quali porte sono accessibili. Verifica inoltre lo stato di salute dei container. Tutti questi dati vengono trasmessi a un Registro dei servizi, che è un database di combinazioni IP:Porta. I servizi Roblox utilizzano il Registro dei servizi per individuarsi a vicenda in modo da poter comunicare. Questo processo è chiamato "service discovery". Utilizziamo Consul per la service discovery, i controlli di integrità, il blocco delle sessioni (per i sistemi HA costruiti sopra) e come archivio KV.
Consul viene distribuito come un cluster di macchine con due ruoli. I "votanti" (5 macchine) mantengono in modo autorevole lo stato del cluster; i "non votanti" (5 macchine aggiuntive) sono repliche di sola lettura che assistono nel ridimensionamento delle richieste di lettura. In qualsiasi momento, uno dei votanti viene eletto dal cluster come leader. Il leader è responsabile della replica dei dati agli altri votanti e di determinare se i dati scritti sono stati completamente confermati. Consul utilizza un algoritmo chiamato Raft per l'elezione del leader e per distribuire lo stato all'interno del cluster in modo da garantire che ogni nodo del cluster concordi sugli aggiornamenti. Non è raro che il leader cambi più volte nel corso di una giornata tramite l'elezione del leader.
Quella che segue è una schermata recente della dashboard di Consul presso Roblox dopo l'incidente. Molte delle metriche operative chiave citate in questo post del blog sono mostrate a livelli normali. Il tempo di applicazione KV, ad esempio, è considerato normale se inferiore a 300 ms ed è di 30,6 ms in questo momento. Il leader di Consul ha avuto contatti con altri server del cluster negli ultimi 32 ms, il che è molto recente.

Nei mesi precedenti l'incidente di ottobre, Roblox ha effettuato l'aggiornamento da Consul 1.9 a Consul 1.10 per sfruttare una nuova funzionalità di streaming. Questa funzionalità di streaming è progettata per ridurre in modo significativo la CPU e la larghezza di banda di rete necessarie per distribuire gli aggiornamenti su cluster su larga scala come quello di Roblox.
Rilevamento iniziale (28/10 alle 13:37)
Nel pomeriggio del 28 ottobre, le prestazioni di Vault si sono deteriorate e un singolo server Consul presentava un elevato carico della CPU. Gli ingegneri di Roblox hanno avviato un'indagine. A questo punto i giocatori non erano stati colpiti.
Triage iniziale (28/10 13:37 – 29/10 02:00)
L'indagine iniziale ha suggerito che il cluster Consul da cui dipendono Vault e molti altri servizi non fosse in buone condizioni. Nello specifico, le metriche del cluster Consul mostravano un'elevata latenza di scrittura per l'archivio KV sottostante in cui Consul memorizza i dati. La latenza al 50° percentile su queste operazioni era tipicamente inferiore a 300 ms, ma ora era di 2 secondi. I problemi hardware non sono insoliti su una scala come quella di Roblox e Consul è in grado di sopravvivere a un guasto hardware. Tuttavia, se l'hardware è semplicemente lento anziché guasto, ciò può influire sulle prestazioni complessive di Consul. In questo caso, il team ha sospettato che la causa principale fosse il degrado delle prestazioni hardware e ha avviato il processo di sostituzione di uno dei nodi del cluster Consul. Questo è stato il nostro primo tentativo di diagnosticare l'incidente. In quel periodo, il personale di HashiCorp si è unito agli ingegneri di Roblox per aiutare nella diagnosi e nella risoluzione. Tutti i riferimenti a "il team" e "il team di ingegneri" da questo punto in poi si riferiscono sia al personale di Roblox che a quello di HashiCorp.
Nonostante il nuovo hardware, le prestazioni del cluster Consul continuavano a risentirne. Alle 16:35, il numero di giocatori online è sceso al 50% del normale.

Questo calo ha coinciso con un significativo deterioramento dello stato di salute del sistema, che alla fine ha portato a un'interruzione completa del sistema. Perché? Quando un servizio Roblox vuole comunicare con un altro servizio, si affida a Consul per avere informazioni aggiornate sulla posizione del servizio con cui vuole comunicare. Tuttavia, se Consul non funziona correttamente, i server hanno difficoltà a connettersi. Inoltre, Nomad e Vault si affidano a Consul, quindi quando Consul non funziona correttamente, il sistema non può pianificare nuovi container o recuperare i segreti di produzione utilizzati per l'autenticazione. In breve, il sistema ha fallito perché Consul era un singolo punto di errore e non funzionava correttamente.
A questo punto, il team ha sviluppato una nuova teoria su cosa non funzionasse: l'aumento del traffico. Forse Consul era lento perché il nostro sistema aveva raggiunto un punto di svolta e i server su cui Consul era in esecuzione non riuscivano più a gestire il carico? Questo è stato il nostro secondo tentativo di diagnosticare la causa principale dell'incidente.
Data la gravità dell'incidente, il team ha deciso di sostituire tutti i nodi del cluster Consul con nuove macchine più potenti. Queste nuove macchine avevano 128 core (un aumento del doppio) e dischi SSD NVME più recenti e veloci. Alle 19:00, il team aveva migrato la maggior parte del cluster sulle nuove macchine, ma il cluster non era ancora in stato di salute. Il cluster segnalava che la maggior parte dei nodi non era in grado di stare al passo con le operazioni di scrittura e la latenza al 50° percentile sulle scritture KV era ancora di circa 2 secondi, anziché i tipici 300 ms o meno.
Tentativo n. 1 di ripristino del servizio (29/10, dalle 02:00 alle 04:00)
I primi due tentativi di riportare il cluster Consul a uno stato corretto non hanno avuto successo. Si osservava ancora un'elevata latenza di scrittura KV, oltre a un nuovo sintomo inspiegabile: il leader di Consul era regolarmente fuori sincrono con gli altri votanti.
Il team ha deciso di spegnere l'intero cluster Consul e di ripristinarne lo stato utilizzando uno snapshot di poche ore prima, ovvero l'inizio dell'interruzione. Eravamo consapevoli che ciò avrebbe potenzialmente comportato una piccola perdita di dati di configurazione del sistema (non di dati utente). Data la gravità dell'interruzione e la nostra fiducia nel poter ripristinare manualmente questi dati di configurazione del sistema se necessario, abbiamo ritenuto che fosse accettabile.
Ci aspettavamo che il ripristino da uno snapshot preso quando il sistema era in buono stato avrebbe riportato il cluster in uno stato sano, ma avevamo un'ulteriore preoccupazione. Anche se Roblox non aveva alcun traffico generato dagli utenti che fluiva attraverso il sistema a quel punto, i servizi interni di Roblox erano ancora attivi e si rivolgevano diligentemente a Consul per conoscere la posizione delle loro dipendenze e per aggiornare le loro informazioni di integrità. Queste operazioni di lettura e scrittura stavano generando un carico significativo sul cluster. Temevamo che questo carico potesse riportare immediatamente il cluster in uno stato non funzionante, anche se il ripristino del cluster avesse avuto esito positivo. Per affrontare questa preoccupazione, abbiamo configurato iptables sul cluster per bloccare l'accesso. Questo ci avrebbe permesso di riavviare il cluster in modo controllato e ci avrebbe aiutato a capire se il carico che stavamo esercitando su Consul, indipendentemente dal traffico degli utenti, fosse parte del problema.
Il ripristino è andato liscio e, inizialmente, le metriche sembravano buone. Quando abbiamo rimosso il blocco di iptables, il carico del service discovery e degli health check dai servizi interni è tornato come previsto. Tuttavia, le prestazioni di Consul hanno ricominciato a peggiorare e alla fine siamo tornati al punto di partenza: il 50° percentile sulle operazioni di scrittura KV era di nuovo a 2 secondi. I servizi che dipendevano da Consul stavano iniziando a contrassegnarsi come "non integri" e, alla fine, il sistema è ricaduto nel ormai familiare stato problematico. Erano ormai le 04:00. C'era chiaramente qualcosa nel nostro carico su Consul che causava problemi e, a oltre 14 ore dall'inizio dell'incidente, non sapevamo ancora di cosa si trattasse.
Tentativo n. 2 di ripristino del servizio (29/10 alle 04:00 – 30/10 alle 02:00)
Avevamo escluso un guasto hardware. Un hardware più veloce non era servito e, come abbiamo scoperto in seguito, aveva potenzialmente compromesso la stabilità. Anche il ripristino dello stato interno di Consul non era servito. Non c'era traffico in entrata da parte degli utenti, eppure Consul era ancora lento. Avevamo utilizzato iptables per consentire al traffico di rientrare lentamente nel cluster. Il cluster veniva semplicemente riportato in uno stato non sano dall'enorme volume di migliaia di container che cercavano di riconnettersi? Questo era il nostro terzo tentativo di diagnosticare la causa principale dell'incidente.
Il team di ingegneri ha deciso di ridurre l'utilizzo di Consul e poi reintrodurlo con attenzione e in modo sistematico. Per assicurarci di avere un punto di partenza pulito, abbiamo anche bloccato il traffico esterno rimanente. Abbiamo stilato un elenco esaustivo dei servizi che utilizzano Consul e abbiamo implementato modifiche alla configurazione per disabilitare tutti gli utilizzi non essenziali. Questo processo ha richiesto diverse ore a causa dell'ampia varietà di sistemi e tipi di modifiche alla configurazione interessati. I servizi Roblox che in genere avevano centinaia di istanze in esecuzione sono stati ridotti a poche unità. La frequenza dei controlli di integrità è stata ridotta da 60 secondi a 10 minuti per dare al cluster un po' di respiro in più. Alle 16:00 del 29 ottobre, oltre 24 ore dopo l'inizio dell'interruzione, il team ha avviato il secondo tentativo di riportare Roblox online. Ancora una volta, la fase iniziale di questo tentativo di riavvio sembrava promettente, ma alle 02:00 del 30 ottobre Consul era nuovamente in uno stato non sano, questa volta con un carico significativamente inferiore da parte dei servizi Roblox che dipendono da esso.
A questo punto, era chiaro che l'utilizzo complessivo di Consul non era l'unico fattore che contribuiva al degrado delle prestazioni che avevamo notato per la prima volta il 28. Data questa consapevolezza, il team ha cambiato nuovamente rotta. Invece di guardare a Consul dalla prospettiva dei servizi Roblox che dipendono da esso, il team ha iniziato a esaminare le parti interne di Consul alla ricerca di indizi.
Ricerca sulla contesa (30/10 02:00 – 30/10 12:00)
Nelle 10 ore successive, il team di ingegneri ha approfondito i log di debug e le metriche a livello di sistema operativo. Questi dati hanno mostrato che le scritture KV di Consul venivano bloccate per lunghi periodi di tempo. In altre parole, si verificava una "contesa". La causa della contesa non era immediatamente evidente, ma una teoria era che il passaggio da server con 64 a 128 core CPU all'inizio dell'interruzione potesse aver aggravato il problema. Dopo aver esaminato i dati htop e i dati di debug delle prestazioni mostrati negli screenshot qui sotto, il team ha concluso che valeva la pena tornare a server a 64 core simili a quelli utilizzati prima dell’interruzione. Il team ha iniziato a preparare l’hardware: Consul è stato installato, le configurazioni del sistema operativo sono state ricontrollate tre volte e le macchine sono state preparate per il servizio nel modo più dettagliato possibile. Il team ha quindi riportato il cluster Consul su server a 64 core, ma questa modifica non ha risolto il problema. Questo è stato il nostro quarto tentativo di individuare la causa principale dell'incidente.


Individuate le cause alla radice (30/10 12:00 – 30/10 20:00)
Diversi mesi fa abbiamo attivato una nuova funzionalità di streaming di Consul su una parte dei nostri servizi. Questa funzionalità, progettata per ridurre l'utilizzo della CPU e la larghezza di banda di rete del cluster Consul, ha funzionato come previsto, quindi nei mesi successivi l'abbiamo attivata in modo incrementale su un numero maggiore dei nostri servizi di backend. Il 27 ottobre alle 14:00, un giorno prima dell'interruzione del servizio, abbiamo attivato questa funzionalità su un servizio di backend responsabile dell'instradamento del traffico. Come parte di questa implementazione, al fine di prepararci all'aumento di traffico che tipicamente si verifica a fine anno, abbiamo anche aumentato del 50% il numero di nodi che supportano l'instradamento del traffico. Il sistema aveva funzionato bene con lo streaming a questo livello per un giorno prima che l'incidente iniziasse, quindi inizialmente non era chiaro perché le sue prestazioni fossero cambiate. Tuttavia, attraverso l'analisi dei report di performance e dei flame graph dei server Consul, abbiamo individuato prove che indicavano come i percorsi di codice dello streaming fossero responsabili della contesa che causava l'elevato utilizzo della CPU. Abbiamo disabilitato la funzionalità di streaming per tutti i sistemi Consul, compresi i nodi di instradamento del traffico. La propagazione della modifica di configurazione si è completata alle 15:51, momento in cui il 50° percentile per le scritture KV di Consul è sceso a 300 ms. Finalmente avevamo fatto un passo avanti.
Perché lo streaming era un problema? HashiCorp ha spiegato che, sebbene lo streaming fosse nel complesso più efficiente, nella sua implementazione utilizzava meno elementi di controllo della concorrenza (canali Go) rispetto al long polling. In condizioni di carico molto elevato – in particolare, sia un carico di lettura molto elevato che un carico di scrittura molto elevato – il design dello streaming aggrava la quantità di contesa su un singolo canale Go, il che causa il blocco durante le scritture, rendendolo significativamente meno efficiente. Questo comportamento spiegava anche l’effetto dei server con un numero maggiore di core: quei server erano architetture dual socket con un modello di memoria NUMA. La contesa aggiuntiva sulle risorse condivise peggiorava quindi con questa architettura. Disattivando lo streaming, abbiamo migliorato notevolmente lo stato di salute del cluster Consul.
Nonostante la svolta, non eravamo ancora fuori pericolo. Abbiamo visto Consul eleggere a intermittenza nuovi leader del cluster, il che era normale, ma abbiamo anche visto alcuni leader mostrare gli stessi problemi di latenza che avevamo osservato prima di disabilitare lo streaming, il che non era normale. Senza indizi evidenti che indicassero la causa principale del problema dei leader lenti, e con l'evidenza che il cluster funzionava correttamente fintanto che determinati server non venivano eletti come leader, il team ha preso la decisione pragmatica di aggirare il problema impedendo ai leader problematici di rimanere eletti. Ciò ha permesso al team di concentrarsi sul ripristino dello stato di salute dei servizi Roblox che si affidano a Consul.
Ma cosa stava succedendo con i leader lenti? Non siamo riusciti a capirlo durante l'incidente, ma gli ingegneri di HashiCorp hanno determinato la causa principale nei giorni successivi all'interruzione. Consul utilizza una popolare libreria di persistenza open source chiamata BoltDB per memorizzare i log Raft. Non viene utilizzata per memorizzare lo stato attuale all'interno di Consul, ma piuttosto un log a rotazione delle operazioni in corso di applicazione. Per impedire che BoltDB cresca all'infinito, Consul esegue regolarmente degli snapshot. L'operazione di snapshot scrive lo stato attuale di Consul su disco e poi elimina le voci di log più vecchie da BoltDB.
Tuttavia, a causa del design di BoltDB, anche quando le voci di log più vecchie vengono eliminate, lo spazio che BoltDB occupa sul disco non si riduce mai. Al contrario, tutte le pagine (segmenti da 4 KB all'interno del file) che sono state utilizzate per memorizzare i dati eliminati vengono invece contrassegnate come "libere" e riutilizzate per le scritture successive. BoltDB tiene traccia di queste pagine libere in una struttura chiamata "freelist". In genere, la latenza di scrittura non è influenzata in modo significativo dal tempo necessario per aggiornare la freelist, ma il carico di lavoro di Roblox ha messo in luce un problema di prestazioni patologico in BoltDB che ha reso la manutenzione della freelist estremamente onerosa.
Ripristino del servizio di caching (30/10 20:00 – 31/10 05:00)
Erano trascorse 54 ore dall'inizio dell'interruzione. Con lo streaming disabilitato e un processo in atto per impedire che i leader lenti rimanessero eletti, Consul era ora costantemente stabile. Il team era pronto a concentrarsi sul ripristino del servizio.
Roblox utilizza un tipico modello di microservizi per il proprio backend. Alla base dello "stack" dei microservizi ci sono database e cache. Questi database non sono stati interessati dall'interruzione, ma il sistema di caching, che gestisce regolarmente 1 miliardo di richieste al secondo attraverso i suoi molteplici livelli durante il normale funzionamento del sistema, non era in condizioni ottimali. Poiché le nostre cache memorizzano dati transitori che possono essere facilmente ripopolati dai database sottostanti, il modo più semplice per riportare il sistema di caching in uno stato ottimale era quello di ridistribuirlo.
Il processo di ridistribuzione della cache ha incontrato una serie di problemi:
- Probabilmente a causa del reset dello snapshot del cluster Consul eseguito in precedenza, i dati di scheduling interni che il sistema di cache memorizza nel KV di Consul erano errati.
- Le distribuzioni di cache di piccole dimensioni richiedevano più tempo del previsto, mentre quelle di cache di grandi dimensioni non venivano completate. Si è scoperto che c'era un nodo non funzionante che lo scheduler dei lavori vedeva come completamente aperto anziché non funzionante. Ciò ha portato lo scheduler dei lavori a tentare di pianificare in modo aggressivo i lavori di cache su questo nodo, il che ha fallito perché il nodo non funzionava.
- Lo strumento di distribuzione automatizzata del sistema di cache era stato progettato per supportare adeguamenti incrementali a distribuzioni su larga scala che gestivano già traffico su larga scala, non tentativi iterativi di avviare un grande cluster da zero.
Il team ha lavorato tutta la notte per identificare e risolvere questi problemi, garantire che i sistemi di cache fossero distribuiti correttamente e verificarne la correttezza. Alle 05:00 del 31 ottobre, 61 ore dall'inizio dell'interruzione, avevamo un cluster Consul funzionante e un sistema di cache funzionante. Eravamo pronti a riavviare il resto di Roblox.
Il ritorno dei giocatori (31/10 05:00 – 31/10 16:00)
La fase finale di ripristino del servizio è iniziata ufficialmente alle 05:00 del 31. Analogamente al sistema di cache, una parte significativa dei servizi in esecuzione era stata arrestata durante l’interruzione iniziale o le fasi di risoluzione dei problemi. Il team doveva riavviare questi servizi ai livelli di capacità corretti e verificare che funzionassero correttamente. Tutto è andato liscio e alle 10:00 eravamo pronti a riaprire ai giocatori.
Con le cache vuote e un sistema di cui non eravamo ancora certi, non volevamo un'ondata di traffico che potesse potenzialmente riportare il sistema in uno stato instabile. Per evitare un'ondata, abbiamo utilizzato lo steering DNS per gestire il numero di giocatori che potevano accedere a Roblox. Questo ci ha permesso di far entrare una certa percentuale di giocatori selezionati casualmente, mentre gli altri continuavano a essere reindirizzati alla nostra pagina di manutenzione statica. Ogni volta che aumentavamo la percentuale, controllavamo il carico del database, le prestazioni della cache e la stabilità generale del sistema. Il lavoro è proseguito per tutta la giornata, aumentando l'accesso con incrementi di circa il 10%. Ci ha fatto piacere vedere alcuni dei nostri giocatori più affezionati capire il nostro schema di reindirizzamento DNS e iniziare a scambiarsi queste informazioni su Twitter in modo da poter ottenere un accesso "anticipato" man mano che ripristinavamo il servizio. Alle 16:45 di domenica, 73 ore dopo l'inizio dell'interruzione, il 100% dei giocatori ha ottenuto l'accesso e Roblox era pienamente operativo.
Ulteriori analisi e modifiche derivanti dall'interruzione
Sebbene ai giocatori fosse stato permesso di tornare su Roblox il 31 ottobre, Roblox e HashiCorp hanno continuato ad affinare la loro comprensione dell'interruzione per tutta la settimana successiva. Sono stati identificati e isolati specifici problemi di contesa nel nuovo protocollo di streaming. Sebbene HashiCorp avesse effettuato benchmark dello streaming su una scala simile a quella di utilizzo di Roblox, non aveva mai osservato questo comportamento specifico in precedenza, poiché esso si manifestava a causa di una combinazione di un numero elevato di stream e un alto tasso di abbandono. Il team di ingegneri di HashiCorp sta creando nuovi benchmark di laboratorio per riprodurre il problema specifico di contesa e sta eseguendo ulteriori test di scalabilità. HashiCorp sta inoltre lavorando per migliorare la progettazione del sistema di streaming al fine di evitare la contesa in condizioni di carico estremo e garantire prestazioni stabili in tali condizioni.
Un'ulteriore analisi del problema dello "slow leader" ha inoltre rivelato la causa principale delle scritture di dati Raft di due secondi e dei problemi di coerenza del cluster. Gli ingegneri hanno esaminato grafici a fiamma come quello riportato di seguito per comprendere meglio il funzionamento interno di BoltDB.


L'output del comando precedente ci dice diverse cose:
- Questo archivio di log da 4,2 GB contiene solo 489 MB di dati effettivi (compresi tutti gli elementi interni dell'indice). 3,8 GB sono spazio "vuoto".
- La lista libera è di 7,8 MB poiché contiene quasi un milione di ID di pagine libere.
Ciò significa che, per ogni aggiunta al log (ogni scrittura Raft dopo un certo batching), veniva scritta su disco anche una nuova lista libera da 7,8 MB, anche se i dati grezzi effettivi aggiunti erano pari o inferiori a 16 kB.
La contropressione su queste operazioni ha anche creato buffer TCP pieni e ha contribuito a tempi di scrittura di 2-3 secondi sui leader non funzionanti. L'immagine qui sotto mostra la ricerca su TCP Zero Windows durante l'incidente.

HashiCorp e Roblox hanno sviluppato e implementato un processo che utilizza gli strumenti BoltDB esistenti per "compattare" il database, risolvendo così i problemi di prestazioni.
Miglioramenti recenti e passi futuri
Sono passati due mesi e mezzo dall'interruzione del servizio. Cosa abbiamo fatto in questo periodo? Abbiamo utilizzato questo tempo per imparare il più possibile dall'interruzione del servizio, per adeguare le priorità ingegneristiche sulla base di quanto appreso e per rafforzare in modo aggressivo i nostri sistemi. Uno dei valori di Roblox è "Rispettare la comunità" e, sebbene avremmo potuto pubblicare un post prima per spiegare cosa fosse successo, abbiamo ritenuto di doverlo alla nostra comunità: compiere progressi significativi nel miglioramento dell'affidabilità dei nostri sistemi prima della pubblicazione.
L'elenco completo dei miglioramenti all'affidabilità completati e in corso è troppo lungo e troppo dettagliato per questo articolo, ma ecco i punti chiave:
Miglioramenti alla telemetria
C'era una dipendenza circolare tra i nostri sistemi di telemetria e Consul, il che significava che quando Consul non funzionava correttamente, ci mancavano i dati di telemetria che ci avrebbero permesso di capire più facilmente cosa non andava. Abbiamo rimosso questa dipendenza circolare. I nostri sistemi di telemetria non dipendono più dai sistemi che sono configurati per monitorare.
Abbiamo esteso i nostri sistemi di telemetria per fornire una migliore visibilità sulle prestazioni di Consul e BoltDB. Ora riceviamo avvisi altamente mirati se ci sono segni che il sistema si sta avvicinando allo stato che ha causato questa interruzione. Abbiamo anche esteso i nostri sistemi di telemetria per fornire maggiore visibilità sui modelli di traffico tra i servizi Roblox e Consul. Questa maggiore visibilità sul comportamento e sulle prestazioni del nostro sistema a più livelli ci ha già aiutato durante gli aggiornamenti di sistema e le sessioni di debug.
Espansione in più zone di disponibilità e data center
L'esecuzione di tutti i servizi di backend di Roblox su un unico cluster Consul ci ha esposti a un'interruzione di questo tipo. Abbiamo già realizzato i server e la rete per un data center aggiuntivo, geograficamente distinto, che ospiterà i nostri servizi di backend. Stiamo lavorando per passare a più zone di disponibilità all'interno di questi data center; abbiamo apportato modifiche significative alla nostra roadmap ingegneristica e ai nostri piani di assunzione per accelerare questi sforzi.
Aggiornamenti e sharding di Consul
Roblox sta ancora crescendo rapidamente, quindi, anche con più cluster Consul, vogliamo ridurre il carico che grava su Consul. Abbiamo esaminato il modo in cui i nostri servizi utilizzano l'archivio KV e i controlli di integrità di Consul e abbiamo suddiviso alcuni servizi critici in cluster dedicati, riducendo il carico sul nostro cluster Consul centrale a un livello più sicuro.
Alcuni servizi fondamentali di Roblox utilizzano direttamente l'archivio KV di Consul come luogo conveniente per l'archiviazione dei dati, anche se disponiamo di altri sistemi di archiviazione che sarebbero probabilmente più appropriati. Stiamo procedendo alla migrazione di questi dati verso un sistema di archiviazione più appropriato. Una volta completata, questa operazione ridurrà anche il carico su Consul.
Abbiamo scoperto una grande quantità di dati KV obsoleti. L'eliminazione di questi dati obsoleti ha migliorato le prestazioni di Consul.
Stiamo lavorando a stretto contatto con HashiCorp per implementare una nuova versione di Consul che sostituisca BoltDB con un successore chiamato bbolt, che non presenta lo stesso problema di crescita illimitata della lista libera. Abbiamo intenzionalmente rinviato questo intervento al nuovo anno per evitare un aggiornamento complesso durante il picco di traffico di fine anno. L'aggiornamento è attualmente in fase di test e sarà completato nel primo trimestre.
Miglioramenti alle procedure di bootstrapping e alla gestione della configurazione
Il ripristino del servizio è stato rallentato da una serie di fattori, tra cui l'implementazione e il riscaldamento delle cache necessarie ai servizi Roblox. Stiamo sviluppando nuovi strumenti e processi per rendere questa procedura più automatizzata e meno soggetta a errori. In particolare, abbiamo riprogettato i nostri meccanismi di implementazione della cache per garantire di poter avviare rapidamente il nostro sistema di cache da zero. L'implementazione di questa soluzione è in corso.
Abbiamo collaborato con HashiCorp per identificare diversi miglioramenti a Nomad che ci consentiranno di avviare più facilmente lavori di grandi dimensioni dopo un lungo periodo di indisponibilità. Questi miglioramenti saranno implementati nell'ambito del nostro prossimo aggiornamento di Nomad, previsto per la fine di questo mese.
Abbiamo sviluppato e implementato meccanismi per rendere più veloci le modifiche alla configurazione delle macchine.
Reintroduzione dello streaming
Inizialmente abbiamo implementato lo streaming per ridurre l'utilizzo della CPU e la larghezza di banda di rete del cluster Consul. Una volta che una nuova implementazione sarà stata testata su larga scala con il nostro carico di lavoro, prevediamo di reintrodurla con cautela nei nostri sistemi.
Una nota sul cloud pubblico
All'indomani di un'interruzione come questa, è naturale chiedersi se Roblox prenderebbe in considerazione il passaggio al cloud pubblico e l'affidamento a terzi della gestione dei nostri servizi fondamentali di elaborazione, archiviazione e rete.
Un altro dei nostri valori Roblox è "Take The Long View" (Guardare al lungo termine), e questo valore influenza fortemente il nostro processo decisionale. Costruiamo e gestiamo la nostra infrastruttura di base in loco perché, alla nostra scala attuale e, cosa ancora più importante, alla scala che sappiamo raggiungeremo man mano che la nostra piattaforma cresce, crediamo che sia il modo migliore per supportare la nostra attività e la nostra comunità. In particolare, costruendo e gestendo i nostri data center per i servizi di backend e di rete periferica, siamo stati in grado di controllare significativamente i costi rispetto al cloud pubblico. Questi risparmi influenzano direttamente l’importo che siamo in grado di pagare ai creatori sulla piattaforma. Inoltre, possedere il nostro hardware e costruire la nostra infrastruttura periferica ci permette di ridurre al minimo le variazioni di prestazioni e di gestire con attenzione la latenza dei nostri giocatori in tutto il mondo. Prestazioni costanti e bassa latenza sono fondamentali per l'esperienza dei nostri giocatori, che non si trovano necessariamente vicino ai data center dei fornitori di cloud pubblico.
Si noti che non siamo ideologicamente legati a nessun approccio particolare: utilizziamo il cloud pubblico per i casi d'uso in cui ha più senso per i nostri giocatori e sviluppatori. Ad esempio, utilizziamo il cloud pubblico per la capacità di picco, gran parte dei nostri flussi di lavoro DevOps e la maggior parte delle nostre analisi interne. In generale, riteniamo che il cloud pubblico sia un ottimo strumento per le applicazioni che non sono critiche in termini di prestazioni e latenza e che funzionano su scala limitata. Tuttavia, per i nostri carichi di lavoro più critici in termini di prestazioni e latenza, abbiamo scelto di costruire e gestire la nostra infrastruttura in loco. Abbiamo fatto questa scelta sapendo che richiede tempo, denaro e talento, ma anche sapendo che ci consentirà di costruire una piattaforma migliore. Ciò è coerente con il nostro valore "Take The Long View".
Stabilità del sistema dopo l'interruzione
Roblox riceve in genere un picco di traffico alla fine di dicembre. Abbiamo ancora molto lavoro da fare in termini di affidabilità, ma siamo lieti di comunicare che Roblox non ha registrato un solo incidente significativo di produzione durante il picco di dicembre e che le prestazioni e la stabilità sia di Consul che di Nomad durante questo picco sono state eccellenti. Sembra che i nostri miglioramenti immediati in termini di affidabilità stiano già dando i loro frutti e, man mano che i nostri progetti a lungo termine giungono a conclusione, ci aspettiamo risultati ancora migliori.
Considerazioni finali
Desideriamo ringraziare la nostra comunità globale di Roblox per la comprensione e il sostegno dimostrati. Un altro dei nostri valori Roblox è "Assumersi le proprie responsabilità" e ci assumiamo la piena responsabilità di quanto accaduto. Vorremmo ancora una volta estendere i nostri più sinceri ringraziamenti al team di HashiCorp. I loro ingegneri sono intervenuti per aiutarci all'inizio di questa interruzione senza precedenti e non ci hanno mai abbandonato. Anche ora, a due mesi dall'interruzione, gli ingegneri di Roblox e HashiCorp continuano a collaborare strettamente per garantire che stiamo facendo collettivamente tutto il possibile per impedire che un'interruzione simile si ripeta.
Infine, vogliamo ringraziare i nostri colleghi di Roblox per aver dimostrato perché questo è un posto fantastico in cui lavorare. In Roblox crediamo nella civiltà e nel rispetto. È facile essere civili e rispettosi quando le cose vanno bene, ma la vera prova è come ci trattiamo l’un l’altro quando le cose si fanno difficili. Ad un certo punto, durante un'interruzione di 73 ore, con il tempo che scorreva e lo stress che aumentava, non sarebbe stato sorprendente vedere qualcuno perdere la calma, dire qualcosa di irrispettoso o chiedersi ad alta voce di chi fosse la colpa di tutto questo. Ma non è quello che è successo. Ci siamo sostenuti a vicenda e abbiamo lavorato insieme come un'unica squadra 24 ore su 24 fino a quando il servizio non è tornato a funzionare correttamente. Ovviamente non siamo orgogliosi di questa interruzione e dell'impatto che ha avuto sulla nostra comunità, ma siamo orgogliosi di come ci siamo uniti come squadra per riportare in vita Roblox e di come ci siamo trattati a vicenda con civiltà e rispetto in ogni fase del percorso.
Abbiamo imparato moltissimo da questa esperienza e siamo più che mai determinati a rendere Roblox una piattaforma più forte e affidabile in futuro.
Grazie ancora.
¹ Si noti che tutte le date e gli orari riportati in questo post del blog sono espressi in ora standard del Pacifico (PST).


