Come la cache di Roblox ha sostenuto 1,38 miliardi di QPS oltre i limiti di Redis
Gestire un aumento del traffico di 10 volte all'insegna dell'affidabilità e dell'efficienza

Nell'ambiente di gioco multiplayer su larga scala di Roblox, gli utenti leggono e scrivono dati con un volume e una velocità tali da mandare in tilt i modelli di caching standard. Un utente potrebbe non notare un ritardo di 200 ms su una pagina web standard che memorizza dati statici nella cache, ma un ritardo di 200 ms nel recupero dei dati di interazione o dei metadati del server su Roblox potrebbe bloccare il gameplay e interrompere il mondo di gioco simulato. Roblox opera su un ecosistema di dati imprevedibili, ad alta velocità ed effimeri che devono essere recuperati in pochi millisecondi per preservare l'immersione.
Il nostro livello di caching è progettato per fungere da enorme ammortizzatore tra milioni di utenti simultanei e il nostro storage persistente. Gestisce un carico di picco di 1,38 miliardi di query al secondo (QPS), con singoli cluster logici che superano i 100 milioni di QPS. In questo post, sveleremo come abbiamo progettato un servizio di caching federato per scalare oltre i limiti dei nodi Redis® e ottenere un throughput massiccio, il tutto mentre gestiamo un'impennata di traffico senza precedenti, pari a 10 volte il normale, sul nostro cluster più grande.

Superare i limiti del settore per soddisfare le esigenze in continua crescita
In Roblox, il nostro servizio di caching è basato sulla tecnologia Redis® e un cluster Redis® ha il potenziale per supportare fino a 1.000 nodi. Tuttavia, il limite empirico e accettato dal settore è molto più basso: circa 400-500 nodi.1 Ciò è dovuto al protocollo Gossip decentralizzato di Redis®, che utilizza la comunicazione tra nodi per condividere informazioni su integrità, stato e mappatura degli shard. In cluster più grandi di qualche centinaio di nodi, il traffico generato dal protocollo Gossip inizia a consumare notevoli risorse di CPU e di rete. Ogni nodo deve elaborare gli aggiornamenti di stato provenienti da un numero sempre crescente di peer, sottraendo risorse al compito principale di fornire dati a bassa latenza. Questo overhead del piano di controllo può portare a instabilità e prestazioni imprevedibili, motivo per cui i fornitori di cloud gestito impongono limiti ai nodi. Si tratta di un limite pratico che non può essere superato senza compromettere l’affidabilità.
Questo limite pratico per singolo cluster non è sufficiente a supportare una piattaforma che opera alla scala di Roblox, dove il servizio di backend più grande richiedeva oltre 100 milioni di QPS da uno dei nostri cluster Redis® logici nei momenti di picco, in aumento rispetto ai 10 milioni di tre mesi prima.
Abbiamo adottato un'architettura federata per superare questa limitazione architettonica, posizionando un proxy inverso client davanti a più cluster Redis® più piccoli e indipendenti. Utilizziamo un limite di 400 nodi per cluster per garantire prestazioni prevedibili.
Dal punto di vista delle nostre migliaia di applicazioni e servizi, il proxy inverso client presenta questi cluster disparati come un servizio di caching unico, unificato e scalabile. Questa federazione ci consente di scalare orizzontalmente quasi senza limiti semplicemente aggiungendo più cluster alla federazione, aggirando completamente i vincoli del protocollo Gossip. Oggi, la nostra più grande implementazione di caching singola è composta da oltre 6.000 nodi Redis®, supportati da oltre 15 cluster Redis® indipendenti: una scala resa possibile solo da questo modello federato.

Il processo di migrazione in tre fasi
Passare da una configurazione tradizionale a un'architettura federata gestendo centinaia di cluster di produzione attivi è stata un'impresa notevole. Alla fine del 2024, molti di questi cluster stavano già raggiungendo il nostro limite di 400 nodi, rendendo urgente il passaggio a un modello con maggiore capacità. La sfida principale era che le istanze Redis® standard operano in modo isolato e non hanno una consapevolezza intrinseca degli altri cluster, rendendo necessario un metodo personalizzato per replicare i dati durante il trasferimento.
Per risolvere questo problema, abbiamo sviluppato una pipeline di migrazione trasparente in tre fasi, progettata per trasferire i servizi senza alcun coinvolgimento del cliente o modifiche a livello di applicazione.
Il flusso di lavoro di migrazione
- Doppia scrittura: abbiamo configurato il proxy inverso del client per eseguire doppie scritture, inviando i dati in entrata sia al cluster originale che alla nuova destinazione federata contemporaneamente.
- Parità e commutazione in lettura: una volta che il processo di doppia scrittura ha popolato il nuovo cluster con dati identici, poiché tutti i dati sono vincolati da un tempo di vita (TTL), abbiamo trasferito il traffico di lettura dal cluster legacy alla nuova architettura federata.
- Messa fuori servizio: dopo aver verificato la stabilità del nuovo cluster, abbiamo interrotto tutte le operazioni di scrittura sul cluster originale e lo abbiamo messo fuori servizio.
Abbiamo trasferito con successo i nostri servizi più critici in un modello federato che supporta oltre 6.000 nodi, superando di gran lunga i limiti di un singolo cluster Redis®.
Gestire la crescita esplosiva di Grow a Garden
A partire dall'aprile 2025, abbiamo affrontato una sfida di capacità di una portata che pochi servizi incontrano. Il catalizzatore è stato il fenomenale successo di Grow a Garden. Nel giro di poche settimane dal lancio, Grow a Garden ha iniziato a battere non solo i record di Roblox, ma anche i record storici del settore dei giochi per numero di utenti simultanei (CCU). In soli tre mesi, il pubblico del gioco ha superato il nostro precedente record di CCU per un singolo gioco, pari a 2,8 milioni di giocatori, raggiungendo un picco di oltre 21 milioni. Questa crescita esplosiva ha generato un traffico 10 volte superiore al nostro più grande cluster Redis® e 3 volte superiore al caching complessivo.
Roblox gestisce i propri sistemi di caching su macchine fisiche nei propri data center e questa crescita senza precedenti non rientrava nel piano di capacità a lungo termine. Per sopravvivere a questa ondata e mantenere stabile la piattaforma, abbiamo dovuto migliorare radicalmente l'efficienza della nostra infrastruttura esistente, dando priorità all'affidabilità.
Miglioramento dell'efficienza durante il picco
In primo luogo, dovevamo identificare i colli di bottiglia più significativi nel nostro sistema in modo da poter dare priorità al lavoro di ottimizzazione. Roblox Caching funziona su due diversi pool hardware: uno per i nodi backend Redis® e uno per Envoy. La nostra flotta Redis® è principalmente vincolata alla memoria, mentre il proxy client è vincolato alla potenza di calcolo.
Per la nostra flotta Redis® vincolata alla memoria, abbiamo implementato una nuova politica di scheduling per bilanciare meglio l'utilizzo della memoria tra i nostri gruppi di macchine fisiche. Abbiamo anche ottimizzato le dimensioni dei container per ridurre la frammentazione della memoria.
Per migliorare l'utilizzo della CPU, abbiamo implementato due ottimizzazioni chiave nel nostro sistema di cache:
- Autoscaling del proxy client: abbiamo modificato la politica di autoscaling per la nostra flotta di proxy client vincolata alla potenza di calcolo. Riducendo la deviazione consentita dalla CPU target, abbiamo ottenuto un utilizzo medio della CPU più elevato per i lavori senza modificare la soglia di scale-up.
- Controlli di integrità del cluster interno: abbiamo ottimizzato i controlli di integrità interni per eliminare gli heartbeat non necessari, preservando l'intervallo di rilevamento originale e risparmiando risorse di calcolo.
Queste modifiche hanno portato a un miglioramento di quasi il 10% nell'utilizzo della CPU. Infine, abbiamo collocato questi due carichi di lavoro molto diversi nello stesso pool di macchine con isolamento a livello di container cgroup, il che ha ridotto le nostre esigenze di capacità complessive del 25%.
Progettazione per un'affidabilità incrollabile
L'affidabilità è rimasta la nostra priorità assoluta, anche mentre ci affrettavamo a soddisfare una domanda da record.
Osservabilità end-to-end
Ci siamo concentrati innanzitutto sulla comprensione dei potenziali guasti, investendo massicciamente nel nostro stack di osservabilità per un monitoraggio completo e end-to-end dello stato di salute del nostro sistema di caching. Tracciando i successi del server e i guasti lato client durante l'intero ciclo di vita delle richieste, abbiamo rapidamente individuato e diagnosticato i problemi, spesso prevenendo l'impatto sugli utenti. Ad esempio, abbiamo aggiunto il rilevamento delle chiavi calde, che campiona il traffico in tempo reale per identificare i dati a cui si accede in modo eccessivo e che mettono a dura prova il livello di caching. Quando il sistema segnala una chiave calda, possiamo limitare in modo proattivo il traffico verso queste chiavi sia sul lato server che su quello client per evitare il sovraccarico del sistema.
Gestione degli errori
In qualsiasi sistema distribuito di queste dimensioni, a volte si verificano errori parziali. Abbiamo progettato il nostro sistema per gestire questi errori in modo elegante e ridurne al minimo l'impatto.
- Errori parziali nelle richieste in batch: abbiamo riprogettato il sistema per gestire gli errori parziali nelle richieste in batch. In precedenza, un singolo errore di richiesta in una richiesta in batch frammentata causava il fallimento dell'intero batch. Ora le richieste possono andare a buon fine anche se alcune chiavi non vengono recuperate.
- Mitigazione dell'head-of-line blocking: ci si aspetta che i sistemi di caching siano veloci. Anche un leggero rallentamento della rete può causare l'accumulo di richieste e il timeout, un fenomeno noto come head-of-line blocking. Abbiamo implementato meccanismi di riprova intelligenti e strategie di pooling delle connessioni sia nel livello client che in quello proxy per impedire che una singola richiesta lenta influisca sulle altre.
- Iniezione di errori e latenza: per testare la resilienza, iniettiamo regolarmente errori controllati (interruzioni dei nodi, interruzioni dei rack, latenza di rete, errori API) nell'ambiente di produzione utilizzando il nostro framework di iniezione di errori. Analizzando il comportamento del sistema in queste condizioni, identifichiamo e risolviamo in modo proattivo i punti deboli, garantendo un'affidabilità continua.
Resilienza lato client
Per evitare che il nostro sistema di caching venga sopraffatto da improvvisi picchi di traffico, abbiamo implementato una solida resilienza ai guasti lato client. Questo meccanismo opera a livello di applicazione, garantendo che nessun singolo servizio possa monopolizzare le risorse della cache.
- Limitazione della velocità per il controllo del flusso: il nostro client ha un limite sul traffico in uscita totale, assicurando che non invii più richieste di quante il servizio di backend possa gestire. Le richieste vengono limitate quando questo limite viene superato, il che impedisce al servizio di essere sovraccaricato.
- Meccanismi di riprova e timeout: le nostre librerie client utilizzano meccanismi di riprova accuratamente ottimizzati, inclusi timeout e un budget di riprova, per prevenire problemi di "thundering herd". Ciò limita il raggio d'azione, libera risorse e migliora la reattività complessiva del sistema, impedendo che blocchi indefiniti e riprove simultanee sovraccarichino il sistema.

Il futuro del caching di Roblox
Il percorso di Roblox nel campo della cache è iniziato con cluster Redis® bare-metal gestiti direttamente da ciascun proprietario dell'applicazione, per poi passare a cluster Memcached gestiti dal nostro team di cache e infine transitare verso un modello Redis®-as-a-service, in cui un cluster Redis® viene fornito come servizio gestito. Sebbene questo modello si sia dimostrato altamente efficace alla nostra attuale scala, ne riconosciamo i limiti in termini di efficienza del servizio e isolamento delle risorse per una piattaforma dinamica come Roblox.
Man mano che la piattaforma continua a crescere, abbiamo in programma di effettuare un investimento significativo in un servizio di caching multitenant di nuova generazione basato su ValKey. Questa architettura è progettata per ridurre drasticamente i costi condividendo risorse comuni attraverso il multitenancy, garantendo al contempo l'isolamento di dati, risorse e guasti per ogni tenant. Il nostro obiettivo è migliorare notevolmente le prestazioni, la scalabilità, l'affidabilità e l'efficienza in termini di costi della nostra infrastruttura di caching per soddisfare le esigenze di esperienze sempre più imponenti su Roblox.
Ringraziamenti:
Questo risultato è frutto di uno sforzo collaborativo. Grazie agli altri membri del team che hanno contribuito in modo significativo: Utkarsh Singh, Karthick Ramachandran, Vineesha Kasireddy, Weiji Hu e Leon Gao.
1AWS limita ElasticCache a 500 nodi.
*Redis è un marchio registrato di Redis Labs Ltd. Tutti i diritti sono riservati a Redis Labs Ltd.


