Garantire l'affidabilità delle piattaforme su larga scala

La gestione di qualsiasi piattaforma distribuita scalabile richiede un impegno verso l'affidabilità, per garantire che i clienti abbiano ciò di cui hanno bisogno quando ne hanno bisogno. Le dipendenze potrebbero essere piuttosto complesse, specialmente con una piattaforma grande come Roblox. Costruire servizi affidabili significa che, indipendentemente dalla complessità e dallo stato delle dipendenze, un dato servizio non subirà interruzioni (cioè sarà altamente disponibile), funzionerà senza bug (cioè sarà di alta qualità) e senza errori (cioè sarà tollerante ai guasti).
Perché l'affidabilità è importante
Il nostro team Account Identity si impegna a raggiungere una maggiore affidabilità, poiché i servizi di conformità che abbiamo creato sono componenti fondamentali della piattaforma. Una violazione della conformità può avere gravi conseguenze. Il costo del blocco del normale funzionamento di Roblox è molto elevato, con risorse aggiuntive necessarie per il ripristino dopo un guasto e un'esperienza utente compromessa.
L'approccio tipico all'affidabilità si concentra principalmente sulla disponibilità, ma in alcuni casi i termini vengono confusi e utilizzati in modo improprio. La maggior parte delle misurazioni della disponibilità valuta semplicemente se i servizi sono attivi e funzionanti, mentre aspetti come la tolleranza alle partizioni e la coerenza vengono talvolta dimenticati o fraintesi.
In accordo con il teorema CAP, qualsiasi sistema distribuito può garantire solo due di questi tre aspetti, quindi i nostri servizi di conformità sacrificano una parte della coerenza per essere altamente disponibili e tolleranti alle partizioni. Tuttavia, i nostri servizi hanno sacrificato poco e hanno trovato meccanismi per ottenere una buona coerenza con ragionevoli modifiche architetturali spiegate di seguito.
Il processo per raggiungere una maggiore affidabilità è iterativo, con misurazioni rigorose che si accompagnano a un lavoro continuo al fine di prevenire, individuare, rilevare e correggere i difetti prima che si verifichino incidenti. Il nostro team ha identificato un forte valore nelle seguenti pratiche:
- Misurazione corretta - Costruire una completa osservabilità su come la qualità viene fornita ai clienti e su come le dipendenze forniscono qualità a noi.
- Anticipazione proattiva: svolgere attività quali revisioni architetturali e valutazioni dei rischi delle dipendenze.
- Dare priorità alla correzione - Prestare maggiore attenzione alla risoluzione dei rapporti sugli incidenti per il servizio e le dipendenze collegate al nostro servizio.
Costruire una maggiore affidabilità richiede una cultura della qualità. Il nostro team stava già investendo nello sviluppo orientato alle prestazioni e sa che il successo di un processo dipende dalla sua adozione. Il team ha adottato questo processo nella sua interezza e ha applicato le pratiche come standard. Il diagramma seguente evidenzia le componenti del processo:

Il potere di una misurazione corretta
Prima di approfondire le metriche, è necessario fare una breve precisazione riguardo alle misurazioni del livello di servizio.
- Lo SLO (Obiettivo di Livello di Servizio) è l'obiettivo di affidabilità a cui punta il nostro team (ad es. 99,999%).
- Lo SLI (Service Level Indicator) è l'affidabilità raggiunta in un determinato periodo di tempo (ad esempio, il 99,975% lo scorso febbraio).
- Lo SLA (Accordo sul Livello di Servizio) è l'affidabilità concordata da fornire e che i nostri clienti si aspettano in un determinato periodo di tempo (ad esempio, il 99,99% a settimana).
L'SLI dovrebbe riflettere la disponibilità (nessuna risposta non gestita o mancante), la tolleranza ai guasti (nessun errore di servizio) e la qualità raggiunta (nessun errore imprevisto). Pertanto, abbiamo definito il nostro SLI come il "Success Ratio" delle risposte andate a buon fine rispetto al totale delle richieste inviate a un servizio. Le risposte andate a buon fine sono quelle richieste che sono state inviate in tempo e nella forma corretta, il che significa che non si sono verificati errori di connettività, di servizio o imprevisti.
Questo SLI o Success Ratio viene raccolto dal punto di vista dei consumatori (cioè dei clienti). L'intenzione è quella di misurare l'effettiva esperienza end-to-end fornita ai nostri consumatori, in modo da essere certi che gli SLA siano rispettati. Non farlo creerebbe un falso senso di affidabilità che ignora tutte le preoccupazioni relative all'infrastruttura necessaria per connettersi con i nostri clienti. Analogamente allo SLI dei consumatori, raccogliamo lo SLI delle dipendenze per monitorare qualsiasi potenziale rischio. In pratica, tutti gli SLA di dipendenza dovrebbero allinearsi con lo SLA del servizio e vi è una dipendenza diretta da essi. Il fallimento di uno implica il fallimento di tutti. Monitoriamo e riportiamo anche le metriche del servizio stesso (cioè il server), ma questa non è la fonte pratica per un'elevata affidabilità.
Oltre agli SLI, ogni build raccoglie metriche di qualità che vengono riportate dal nostro flusso di lavoro CI. Questa pratica aiuta a far rispettare rigorosamente i controlli di qualità (ad esempio, la copertura del codice) e a riportare altre metriche significative, come la conformità agli standard di codifica e l'analisi statica del codice. Questo argomento è stato trattato in precedenza in un altro articolo, "Building Microservices Driven by Performance". L'osservanza diligente della qualità è fondamentale quando si parla di affidabilità, perché più investiamo nel raggiungimento di punteggi eccellenti, più siamo sicuri che il sistema non fallirà in condizioni avverse.
Il nostro team dispone di due dashboard. Una fornisce una visione completa sia degli SLI dei consumatori che degli SLI delle dipendenze. La seconda mostra tutte le metriche di qualità. Stiamo lavorando per unificare il tutto in un'unica dashboard, in modo che tutti gli aspetti che ci interessano siano consolidati e pronti per essere riportati in un determinato arco di tempo.
Anticipare i guasti
Effettuare revisioni architetturali è una parte fondamentale per garantire l'affidabilità. Innanzitutto, determiniamo se è presente ridondanza e se il servizio ha i mezzi per sopravvivere quando le dipendenze smettono di funzionare. Al di là delle tipiche idee di replica, la maggior parte dei nostri servizi ha applicato tecniche migliorate di dual cache hydration, strategie di dual recovery (come le code locali di failover) o strategie di protezione dalla perdita di dati (come il supporto transazionale). Questi argomenti sono abbastanza vasti da giustificare un altro post sul blog, ma in definitiva la raccomandazione migliore è quella di implementare idee che prendano in considerazione scenari di disastro e riducano al minimo qualsiasi penalizzazione delle prestazioni.
Un altro aspetto importante da anticipare è tutto ciò che potrebbe migliorare la connettività. Ciò significa puntare con determinazione alla bassa latenza per i client e prepararli a un traffico molto elevato utilizzando tecniche di controllo della cache, sidecar e politiche performanti per timeout, circuit breaker e tentativi di riconnnessione. Queste pratiche si applicano a qualsiasi client, inclusi cache, archivi, code e client interdipendenti in HTTP e gRPC. Significa anche migliorare i segnali di integrità provenienti dai servizi e comprendere che i controlli di integrità svolgono un ruolo importante in tutta l'orchestrazione dei container. La maggior parte dei nostri servizi invia segnali migliori in caso di degrado come parte del feedback del controllo di integrità e verifica che tutti i componenti critici siano funzionanti prima di inviare segnali di integrità.
Suddividere i servizi in parti critiche e non critiche si è rivelato utile per concentrarsi sulle funzionalità che contano di più. In passato avevamo endpoint riservati all'amministratore nello stesso servizio e, sebbene non fossero utilizzati spesso, influivano sulle metriche di latenza complessive. Spostarli in un servizio dedicato ha influito positivamente su ogni metrica.
La valutazione del rischio di dipendenza è uno strumento importante per identificare potenziali problemi con le dipendenze. Ciò significa che identifichiamo le dipendenze con SLI basso e chiediamo l'allineamento dello SLA. Tali dipendenze richiedono un'attenzione particolare durante le fasi di integrazione, quindi dedichiamo tempo extra al benchmarking e ai test per verificare se le nuove dipendenze sono abbastanza mature per i nostri piani. Un buon esempio è l'adozione precoce che abbiamo fatto del Roblox Storage-as-a-Service. L'integrazione con questo servizio ha richiesto la creazione di ticket di bug e riunioni di sincronizzazione periodiche per comunicare i risultati e il feedback. Tutto questo lavoro utilizza il tag "affidabilità", in modo da poter identificare rapidamente la sua origine e le priorità. La caratterizzazione è avvenuta spesso fino a quando non abbiamo avuto la certezza che la nuova dipendenza fosse pronta per noi. Questo lavoro extra ha contribuito a portare la dipendenza al livello di affidabilità richiesto che ci aspettiamo di fornire, agendo insieme per un obiettivo comune.
Dare struttura al caos
Non è mai auspicabile che si verifichino incidenti. Ma quando accadono, ci sono informazioni significative da raccogliere e da cui imparare per essere più affidabili. Il nostro team dispone di un rapporto sugli incidenti di squadra che va oltre il tipico rapporto a livello aziendale, quindi ci concentriamo su tutti gli incidenti indipendentemente dall'entità del loro impatto. Individuiamo la causa principale e diamo priorità a tutto il lavoro necessario per mitigarla in futuro. Come parte di questo rapporto, coinvolgiamo altri team per risolvere gli incidenti di dipendenza ad alta priorità, seguiamo con una risoluzione adeguata, facciamo una retrospettiva e cerchiamo modelli che possano applicarsi a noi.
Il team produce un rapporto mensile sull'affidabilità per ogni servizio che include tutti gli SLI qui spiegati, eventuali ticket aperti a causa di problemi di affidabilità e qualsiasi possibile incidente associato al servizio. Siamo così abituati a generare questi rapporti che il passo successivo naturale è automatizzarne l'estrazione. Svolgere questa attività periodica è importante e ci ricorda che l'affidabilità viene costantemente monitorata e presa in considerazione nel nostro sviluppo.

La nostra strumentazione include metriche personalizzate e avvisi migliorati, in modo da essere avvisati il prima possibile quando si verificano problemi noti e previsti. Tutti gli avvisi, compresi i falsi positivi, vengono esaminati ogni settimana. A questo punto, è importante perfezionare tutta la documentazione affinché i nostri utenti sappiano cosa aspettarsi quando si attivano gli avvisi e quando si verificano errori, e affinché tutti sappiano cosa fare (ad esempio, i playbook e le linee guida di integrazione vengono allineati e aggiornati spesso).
In definitiva, l'adozione della qualità nella nostra cultura è il fattore più critico e decisivo per raggiungere una maggiore affidabilità. Possiamo osservare come queste pratiche applicate al nostro lavoro quotidiano stiano già dando i loro frutti. Il nostro team è ossessionato dall'affidabilità ed è il nostro risultato più importante. Abbiamo aumentato la nostra consapevolezza dell'impatto che i potenziali difetti potrebbero avere e di quando potrebbero verificarsi. I servizi che hanno implementato queste pratiche hanno costantemente raggiunto i propri SLO e SLA. I rapporti sull'affidabilità che ci aiutano a monitorare tutto il lavoro che abbiamo svolto sono una testimonianza del lavoro svolto dal nostro team e rappresentano lezioni inestimabili per informare e influenzare altri team. È così che la cultura dell'affidabilità tocca tutte le componenti della nostra piattaforma.
Il percorso verso una maggiore affidabilità non è facile, ma è necessario se si vuole costruire una piattaforma affidabile che reinventi il modo in cui le persone si riuniscono.
Alberto è Principal Software Engineer nel team Account Identity di Roblox. Lavora nel settore dei videogiochi da molto tempo e ha al suo attivo numerosi titoli AAA e piattaforme di social media, con una forte attenzione alle architetture altamente scalabili. Ora sta aiutando Roblox a raggiungere la crescita e la maturità applicando le migliori pratiche di sviluppo.


