De content op deze site is vertaald met behulp van kunstmatige intelligentie (AI) of machinevertalingstechnologie en kan fouten bevatten.

Skip to content

Hoe Roblox zijn Kafka-platform heeft opgeschaald naar meer dan 18 biljoen berichten per dag

End-to-end-optimalisatie voor efficiënte systemen

In de afgelopen twee jaar hebben we ons interne berichtenwachtrijplatform elk jaar met meer dan 2,5 keer opgeschaald tot meer dan 18 biljoen berichten per dag. Momenteel verwerken we meer dan 300 miljoen berichten per seconde, met een beschikbaarheid van 99,995%. Dit berichtenwachtrijplatform, gebouwd op Apache Kafka, is een cruciaal onderdeel geworden van de manier waarop we gegevens binnen het bedrijf verwerken. Het ondersteunt workloads zoals analyse-events, moderatiepijplijnen, matchmaking-systemen en nog veel meer. Deze cijfers zijn indrukwekkend, maar het belangrijkste verhaal is hoe we dit hebben bereikt. 

De impact van end-to-end-optimalisatie 

Een veelvoorkomende misvatting over grootschalige systemen is dat capaciteit vooral een hardwareprobleem is. Onze ervaring leert dat de meest impactvolle verbeteringen worden gerealiseerd door schaalbaarheid te benaderen als een end-to-end technisch vraagstuk.

Teams binnen Roblox hebben diverse platforms gebouwd bovenop de berichtenwachtrij, waaronder AI-trainingspijplijnen, abstracties voor streamverwerking en telemetriesystemen. Door samen te werken met de beheerders van deze platforms kunnen we ervoor zorgen dat best practices worden nageleefd, zoals het inschakelen van batchverwerking en compressie. Dit resulteert in efficiënte systemen zonder dat eindgebruikers betrokken hoeven te worden bij gedetailleerde configuratie-instellingen.

Dankzij onze wachtrijarchitectuur en bijbehorende platforms kunnen andere teams aan de slag zonder het wiel opnieuw uit te vinden of zich zorgen te maken over de configuratie

Afstemming met teams die het platform gebruiken op het gebied van zakelijke prioriteiten, metingen en succescriteria is van cruciaal belang en stimuleert de samenwerking tussen teams. De belangrijkste statistieken variëren per laag van het systeem: terwijl wij de Kafka-servers wellicht optimaliseren om grote datavolumes efficiënt te verwerken met minder machines, willen eindgebruikers mogelijk optimaliseren voor end-to-end-latentie tot op het millisecondeniveau, of voor de totale tijd die hun batchtaak nodig heeft om het schrijven van gegevens te voltooien. 

Niet al het verkeer is gelijk

Een belangrijke les die we hebben geleerd, is dat grootschalige platforms betrouwbaarder zijn wanneer ze niet al het verkeer op dezelfde manier behandelen. Sommige workloads vereisen een zeer lage latentie en sterke bescherming tijdens pieken, zoals onze matchmaking-systemen, die werken met een end-to-end-latentie van minder dan 10 milliseconden. Andere hebben een extreem hoog volume, maar zijn toleranter ten opzichte van vertraging, zoals onze pijplijnen voor het opnemen van analytische gebeurtenissen, die zelfs bij een end-to-end-latentie van meerdere seconden soepel kunnen draaien. Als beide op identieke wijze worden behandeld, kan het verkeer met het hoogste volume het meer bedrijfskritische verkeer verdringen, vooral tijdens piekbelasting.

Om dit probleem op te lossen, groeperen we het verkeer op basis van de vereisten per gebruiksscenario, zodat elk scenario goed wordt ondersteund. De afweging tussen end-to-end-latentie en doorvoercapaciteit in Kafka is een van de belangrijkste overwegingen bij het opzetten van nieuwe gebruiksscenario’s. Dit geldt voor het gehele datapad van producent naar server naar consument: elk van deze onderdelen heeft configuraties die kunnen worden afgestemd om te optimaliseren voor ofwel doorvoercapaciteit ofwel latentie. Configuraties aan de clientzijde kunnen voor individuele gebruiksscenario’s worden afgestemd, maar configuraties aan de serverzijde zijn minder flexibel, aangezien het onhoudbaar is om voor elk afzonderlijk gebruiksscenario een eigen cluster te onderhouden. 

We passen deze aanpak – waarbij elk cluster wordt geoptimaliseerd voor de use cases die het bedient – door de hele stack heen toe, tot aan de hardwarelaag. 

Hardware blijft cruciaal

We zijn begonnen met het draaien van Kafka op machines met RAID10-HDD’s. Naarmate het verkeersvolume toenam, werd de schijf-I/O-capaciteit van onze machines de belangrijkste bottleneck die de Kafka-doorvoer per server beperkte. Om dit aan te pakken, hebben we twee optimalisaties doorgevoerd. We hebben brokers zo veel mogelijk omgezet naar SSD’s, waardoor de bottleneck verschoof van schijf-I/O-capaciteit naar netwerkdoorvoer of schijfruimte (aangezien de SSD’s die we aanschaften minder schijfruimte hadden). Hierdoor nam de schijf-I/O-doorvoer met een factor 10 toe. Daarnaast zijn we begonnen met het omzetten van onze resterende HDD’s van RAID10 naar RAID0. Dit verdubbelde de schijf-I/O-capaciteit ruwweg, aangezien elke schrijfbewerking met RAID0 slechts één schrijfbewerking op de schijf vereist in plaats van twee. 

Het nadeel is dat, aangezien elke berichtreplica per broker naar één schijf wordt geschreven in plaats van naar twee, de overstap van RAID10 naar RAID0 een risico voor de betrouwbaarheid met zich mee kan brengen. Om de betrouwbaarheid te handhaven, hebben we bij belangrijke use cases gewerkt aan het verhogen van het aantal bevestigingen (acks) en de gegevensreplicatie, inclusief replicatie naar meerdere regio’s.

Om de opslag- en doorvoercapaciteiten van elke machine volledig te benutten, was extra werk nodig. We hebben onze geheugentoewijzingen en de configuraties voor het paginacachebeheer geoptimaliseerd, zodat Kafka berichten kan bufferen en leesverzoeken of recente gegevens vanuit het geheugen kan verwerken, waarbij de schijf alleen wordt geraadpleegd en kostbare IOPS worden verbruikt wanneer dat nodig is, zoals bij het lezen van historische gegevens. 

We voeren ook prestatiebenchmarks uit om de hardwarebeperkingen in kaart te brengen en te bepalen welke beperkingen we op softwareniveau moeten instellen. In de praktijk betekent dit het instellen van lees- en schrijfbeperkingen voor Kafka-brokers, die variëren afhankelijk van de hardware waarop de clusters draaien. Onze SSD-machines kunnen een hogere doorvoercapaciteit per broker aan, terwijl onze HDD-machines beter geschikt zijn voor gebruiksscenario’s waarbij historische gegevens langdurig moeten worden bewaard. 

Bouwen met het oog op betrouwbaarheid

Het wachtrijplatform is een cruciaal onderdeel van de infrastructuur van Roblox, en het handhaven van betrouwbaarheid is van essentieel belang. Zowel tests vóór de lancering als doorlopende tests van storingsscenario’s (ook wel ‘game day exercises’ genoemd) zijn van groot belang geweest om te valideren dat onze infrastructuur bestand is tegen storingsmodi zoals het uitvallen van één host, het uitvallen van een rack, netwerkproblemen en vele andere. Het interne chaos-testplatform van ons betrouwbaarheidsteam heeft het proces van het simuleren van diverse storingsscenario’s mogelijk gemaakt en gestroomlijnd. Deze tests helpen bij het identificeren van systeemverbeteringen of -verslechteringen en dragen bij aan operationele uitmuntendheid door regelmatig waarschuwingen te valideren en ervoor te zorgen dat operators vertrouwd zijn met de stappen om diverse problemen aan te pakken – zelfs zeldzame.

We hebben ook failover-processen ontworpen en geïmplementeerd waarmee de wachtrijfunctionaliteit voor afhankelijke gebruiksscenario’s snel kan worden hersteld. Zelfs in het geval van een totale uitval van een afzonderlijk cluster zijn we in staat om clients over te schakelen naar een gezond cluster met voldoende capaciteit. Om ervoor te zorgen dat we over voldoende ongebruikte capaciteit beschikken, onderhouden we een stand-by Kafka-cluster. Dit helpt het risico op ‘noisy neighbor’-problemen te elimineren bij het verplaatsen van verkeer tussen actieve clusters.

Het onderstaande diagram toont de stappen op hoog niveau voor het uitvoeren van een failover. Eerst bepaalt een operator de omvang van de failover. Vervolgens worden topics en toegangscontrolelijsten (ACL’s) op het stand-bycluster aangemaakt via een geautomatiseerde bulkbewerking. Ten slotte werkt de operator de configuraties van onze control plane-service bij, die door clients worden gepolld om te bepalen of er een herverbinding nodig is. De onderstaande illustratie is bedoeld voor algemene realtime-toepassingen. We beschikken over aanvullende strategieën en tools voor andere gebruiksscenario’s, waaronder het spiegelen van topics met Mirror Maker 2, tools voor het aanvullen van gegevens en meer.

Roblox hanteert strenge beveiligingseisen, wat ook een cruciaal onderdeel is van de betrouwbaarheid. We hebben standaardbeveiligingsfuncties geïmplementeerd, zoals versleuteling tijdens verzending (met mTLS), versleuteling in rust (met versleutelde schijf), vereisten voor de bewaartermijn van gegevens en authenticatie/autorisatie met Kafka-principals en ACL's. Daarnaast wisselen we de inloggegevens van onze gebruikers automatisch af om de beveiliging verder te verbeteren.

Daarnaast hebben we in ons control plane aangepaste verwerking ingebouwd om snelle OS-patches en het leeghalen van racks mogelijk te maken. Tijdens het patchen van het besturingssysteem bewaren we gegevens op de schijf, zodat gepatchte machines snel weer in goede staat kunnen komen nadat ze zich opnieuw bij het Kafka-cluster hebben aangesloten. Op deze manier kunnen we ons gehele machinepark binnen 30 dagen patchen, zelfs terwijl het blijft groeien. Met tools zoals Cruise Control repliceren we onze gegevens op een ‘rack-bewuste’ manier, zodat hele racks offline kunnen worden gehaald voor onderhoud en netwerkpatches zonder dat dit ten koste gaat van de beschikbaarheid van de gegevens.

De weg vooruit

Het volgende hoofdstuk voor ons wachtrijplatform draait om het nog eenvoudiger maken van het platform voor ontwikkelaars, terwijl we de elasticiteit en isolatie blijven verbeteren. We investeren in nieuwe abstracties, waaronder producer- en consumer-proxies en volledig beheerde connectoren. Deze systemen zullen applicatieteams verder ontkoppelen van de complexiteit van de infrastructuur en ervoor zorgen dat onze platforms op schaal gemakkelijker te implementeren en te beheren zijn. Een consumer-proxy maakt bijvoorbeeld het ‘competing consumer’-patroon mogelijk, waardoor het platform een breder scala aan use cases kan ondersteunen en de schaalbaarheid van processors kan loskoppelen van die van Kafka-partities. Dit is waardevol voor use cases zoals het verwerken van massale pieken in meldingen, die geen volgorde vereisen en baat hebben bij het tijdelijk opschalen van het aantal processors zonder dat er eind-tot-eind-leveringsdoelen moeten worden gehaald.

Het opschalen van Kafka gaat niet alleen over het opschalen van het aantal en de grootte van clusters. Het gaat om het opbouwen van de technische discipline, abstracties en het operationele model waarmee Roblox zijn reis kan voortzetten om elke dag een miljard mensen met optimisme en beleefdheid met elkaar te verbinden. 

Dankwoord: Dank aan Danny Yuan en George Li voor hun belangrijke bijdragen aan het Roblox-wachtrijplatform.