Grote betrouwbaarheid van het platform

Het runnen van een schaalbaar gedistribueerd platform vereist een toewijding aan betrouwbaarheid, om ervoor te zorgen dat klanten hebben wat ze nodig hebben wanneer ze het nodig hebben. De afhankelijkheden kunnen behoorlijk ingewikkeld zijn, vooral bij een platform dat zo groot is als Roblox. Het bouwen van betrouwbare diensten betekent dat, ongeacht de complexiteit en status van afhankelijkheden, een bepaalde dienst niet wordt onderbroken (d.w.z. hoge beschikbaarheid), bugvrij werkt (d.w.z. hoge kwaliteit) en foutloos is (d.w.z. fouttolerantie).
Waarom betrouwbaarheid belangrijk is
Ons Account Identity-team streeft naar een hogere betrouwbaarheid, aangezien de compliance-services die we hebben gebouwd kernonderdelen van het platform zijn. Het niet naleven van compliance kan ernstige gevolgen hebben. De kosten van het blokkeren van de normale werking van Roblox zijn zeer hoog, met extra middelen die nodig zijn om te herstellen na een storing en een verminderde gebruikerservaring.
De gebruikelijke benadering van betrouwbaarheid richt zich voornamelijk op beschikbaarheid, maar in sommige gevallen worden termen door elkaar gehaald en verkeerd gebruikt. De meeste metingen voor beschikbaarheid beoordelen alleen of diensten actief zijn, terwijl aspecten zoals partitietolerantie en consistentie soms worden vergeten of verkeerd begrepen.
In overeenstemming met de CAP-stelling kan elk gedistribueerd systeem slechts twee van deze drie aspecten garanderen, dus onze compliance-services offeren enige consistentie op om hoog beschikbaar en partitietolerant te zijn. Niettemin hebben onze services weinig opgeofferd en mechanismen gevonden om een goede consistentie te bereiken met redelijke architecturale wijzigingen, zoals hieronder uitgelegd.
Het proces om een hogere betrouwbaarheid te bereiken is iteratief, waarbij nauwkeurige metingen gepaard gaan met continu werk om defecten te voorkomen, op te sporen, te detecteren en te verhelpen voordat er incidenten plaatsvinden. Ons team heeft grote waarde gezien in de volgende werkwijzen:
- Juiste metingen - Bouw volledige observeerbaarheid op rond de manier waarop kwaliteit aan klanten wordt geleverd en hoe afhankelijkheden kwaliteit aan ons leveren.
- Proactief anticiperen - Voer activiteiten uit zoals architecturale beoordelingen en risicobeoordelingen van afhankelijkheden.
- Prioriteit geven aan correctie - Meer aandacht besteden aan het oplossen van incidentmeldingen voor de dienst en de afhankelijkheden die aan onze dienst zijn gekoppeld.
Het opbouwen van een hogere betrouwbaarheid vereist een kwaliteitscultuur. Ons team investeerde al in prestatiegedreven ontwikkeling en weet dat het succes van een proces afhangt van de acceptatie ervan. Het team heeft dit proces volledig overgenomen en de werkwijzen als standaard toegepast. Het volgende diagram belicht de onderdelen van het proces:

De kracht van de juiste meting
Voordat we dieper ingaan op de statistieken, is er een korte toelichting nodig met betrekking tot de metingen van het serviceniveau.
- SLO (Service Level Objective) is de betrouwbaarheidsdoelstelling die ons team nastreeft (bijv. 99,999%).
- SLI (Service Level Indicator) is de bereikte betrouwbaarheid binnen een bepaald tijdsbestek (bijv. 99,975% afgelopen februari).
- SLA (Service Level Agreement) is de betrouwbaarheid die is overeengekomen en die onze klanten binnen een bepaald tijdsbestek mogen verwachten (bijv. 99,99% per week).
De SLI moet de beschikbaarheid (geen onbehandelde of ontbrekende reacties), de fouttolerantie (geen servicefouten) en de bereikte kwaliteit (geen onverwachte fouten) weerspiegelen. Daarom hebben we onze SLI gedefinieerd als de “succesratio” van succesvolle reacties ten opzichte van het totale aantal verzoeken dat naar een service is verzonden. Succesvolle reacties zijn die verzoeken die op tijd en in de juiste vorm zijn verzonden, wat betekent dat er geen verbindings-, service- of onverwachte fouten zijn opgetreden.
Deze SLI of succesratio wordt verzameld vanuit het perspectief van de consumenten (d.w.z. klanten). Het is de bedoeling om de daadwerkelijke end-to-end-ervaring te meten die aan onze consumenten wordt geleverd, zodat we er zeker van kunnen zijn dat aan de SLA's wordt voldaan. Als we dit niet doen, zou dit een vals gevoel van betrouwbaarheid creëren dat voorbijgaat aan alle infrastructuurproblemen die de verbinding met onze klanten kunnen belemmeren. Net als bij de consumenten-SLI verzamelen we de afhankelijkheids-SLI om mogelijke risico's op te sporen. In de praktijk moeten alle afhankelijkheid-SLA's aansluiten bij de service-SLA en is er een directe afhankelijkheid met deze. Het falen van één impliceert het falen van alle. We volgen en rapporteren ook statistieken van de service zelf (d.w.z. de server), maar dit is niet de praktische bron voor hoge betrouwbaarheid.
Naast de SLI's verzamelt elke build kwaliteitsstatistieken die worden gerapporteerd door onze CI-workflow. Deze werkwijze helpt om kwaliteitscontroles (d.w.z. codedekking) strikt af te dwingen en andere zinvolle statistieken te rapporteren, zoals naleving van coderingsstandaarden en statische codeanalyse. Dit onderwerp is eerder behandeld in een ander artikel, Microservices bouwen op basis van prestaties. Zorgvuldige naleving van kwaliteit telt mee als het gaat om betrouwbaarheid, want hoe meer we investeren in het behalen van uitstekende scores, hoe zekerder we zijn dat het systeem niet zal falen onder ongunstige omstandigheden.
Ons team heeft twee dashboards. Het ene biedt volledig inzicht in zowel de Consumers SLI als de Dependencies SLI. Het tweede toont alle kwaliteitsstatistieken. We werken eraan om alles samen te voegen in één dashboard, zodat alle aspecten die voor ons belangrijk zijn, worden geconsolideerd en klaar zijn om te worden gerapporteerd voor elk gewenst tijdsbestek.
Anticipeer op storingen
Het uitvoeren van architecturale beoordelingen is een fundamenteel onderdeel van betrouwbaarheid. Eerst bepalen we of er redundantie aanwezig is en of de dienst de middelen heeft om te overleven wanneer afhankelijkheden uitvallen. Naast de gebruikelijke replicatieconcepten hebben de meeste van onze services verbeterde dual-cache-hydrationtechnieken, dual-recoverystrategieën (zoals failover van lokale wachtrijen) of strategieën tegen gegevensverlies (zoals transactionele ondersteuning) toegepast. Deze onderwerpen zijn uitgebreid genoeg om een aparte blogpost te rechtvaardigen, maar uiteindelijk is de beste aanbeveling om ideeën te implementeren die rekening houden met rampscenario's en eventuele prestatieverliezen minimaliseren.
Een ander belangrijk aspect om op te anticiperen is alles wat de connectiviteit kan verbeteren. Dat betekent dat we agressief moeten zijn op het gebied van lage latentie voor clients en hen moeten voorbereiden op zeer hoog verkeer met behulp van cache-control-technieken, sidecars en performante beleidsregels voor time-outs, circuit breakers en herhalingspogingen. Deze werkwijzen zijn van toepassing op elke client, inclusief caches, stores, wachtrijen en onderling afhankelijke clients in HTTP en gRPC. Het betekent ook het verbeteren van gezondheidssignalen van de services en het besef dat health checks een belangrijke rol spelen in alle containerorkestratie. De meeste van onze services geven betere signalen af bij verslechtering als onderdeel van de feedback van de health check en controleren of alle kritieke componenten functioneren voordat ze gezondheidssignalen verzenden.
Het opsplitsen van services in kritieke en niet-kritieke onderdelen is nuttig gebleken om ons te concentreren op de functionaliteit die er het meest toe doet. Vroeger hadden we endpoints die alleen voor beheerders waren in dezelfde service, en hoewel deze niet vaak werden gebruikt, hadden ze invloed op de algemene latentie-statistieken. Door ze naar een eigen service te verplaatsen, hadden alle statistieken een positieve invloed.
Dependency Risk Assessment is een belangrijk hulpmiddel om potentiële problemen met afhankelijkheden te identificeren. Dit betekent dat we afhankelijkheden met een lage SLI identificeren en vragen om SLA-afstemming. Die afhankelijkheden hebben speciale aandacht nodig tijdens integratiestappen, dus besteden we extra tijd aan het benchmarken en testen of de nieuwe afhankelijkheden volwassen genoeg zijn voor onze plannen. Een goed voorbeeld is de vroege adoptie die we hadden voor de Roblox Storage-as-a-Service. De integratie met deze service vereiste het indienen van bugtickets en periodieke synchronisatievergaderingen om bevindingen en feedback te communiceren. Al dit werk maakt gebruik van de tag "betrouwbaarheid", zodat we snel de bron en prioriteiten kunnen identificeren. Karakterisering vond vaak plaats totdat we er zeker van waren dat de nieuwe afhankelijkheid klaar was voor ons. Dit extra werk hielp om de afhankelijkheid op het vereiste betrouwbaarheidsniveau te brengen dat we verwachten te leveren door samen te werken aan een gemeenschappelijk doel.
Breng structuur in de chaos
Het is nooit wenselijk dat er incidenten plaatsvinden. Maar wanneer ze zich voordoen, is er waardevolle informatie te verzamelen en te leren om betrouwbaarder te worden. Ons team heeft een teamincidentrapport dat verder gaat dan het gebruikelijke bedrijfsbrede rapport, zodat we ons richten op alle incidenten, ongeacht de omvang van de impact. We brengen de hoofdoorzaak in kaart en stellen prioriteiten voor alle werkzaamheden om deze in de toekomst te beperken. Als onderdeel van dit rapport schakelen we andere teams in om incidenten met hoge prioriteit op te lossen, zorgen we voor een goede follow-up en zoeken we naar patronen die op ons van toepassing kunnen zijn.
Het team stelt per dienst een maandelijks betrouwbaarheidsrapport op met alle hier beschreven SLI's, alle tickets die we hebben geopend vanwege betrouwbaarheidsproblemen en alle mogelijke incidenten die verband houden met de dienst. We zijn zo gewend aan het genereren van deze rapporten dat de volgende logische stap is om de extractie ervan te automatiseren. Het is belangrijk om deze periodieke activiteit uit te voeren, en het herinnert ons eraan dat betrouwbaarheid voortdurend wordt bijgehouden en meegenomen in onze ontwikkeling.

Onze instrumentatie omvat aangepaste statistieken en verbeterde waarschuwingen, zodat we zo snel mogelijk worden gewaarschuwd wanneer bekende en verwachte problemen zich voordoen. Alle waarschuwingen, inclusief valse positieven, worden wekelijks geëvalueerd. Op dit moment is het belangrijk om alle documentatie te verfijnen, zodat onze gebruikers weten wat ze kunnen verwachten wanneer waarschuwingen worden geactiveerd en wanneer er fouten optreden, en zodat iedereen weet wat hij of zij moet doen (bijvoorbeeld door playbooks en integratierichtlijnen op elkaar af te stemmen en regelmatig bij te werken).
Uiteindelijk is het integreren van kwaliteit in onze cultuur de meest cruciale en doorslaggevende factor om een hogere betrouwbaarheid te bereiken. We zien dat deze werkwijzen, toegepast in ons dagelijks werk, nu al hun vruchten afwerpen. Ons team is geobsedeerd door betrouwbaarheid en dat is onze belangrijkste prestatie. We zijn ons meer bewust geworden van de impact die potentiële defecten kunnen hebben en wanneer ze kunnen ontstaan. Diensten die deze werkwijzen hebben geïmplementeerd, hebben hun SLO's en SLA's consequent gehaald. De betrouwbaarheidsrapporten die ons helpen al het werk dat we hebben verricht bij te houden, zijn een bewijs van het werk dat ons team heeft verricht en vormen waardevolle lessen om andere teams te informeren en te beïnvloeden. Zo raakt de betrouwbaarheidscultuur alle onderdelen van ons platform.
De weg naar een hogere betrouwbaarheid is niet gemakkelijk, maar wel noodzakelijk als je een vertrouwd platform wilt bouwen dat een nieuwe invulling geeft aan de manier waarop mensen samenkomen.
Alberto is Principal Software Engineer bij het Account Identity-team van Roblox. Hij is al lange tijd actief in de game-industrie en heeft meegewerkt aan vele AAA-gametitels en sociale mediaplatforms, met een sterke focus op zeer schaalbare architecturen. Nu helpt hij Roblox bij het realiseren van groei en volwassenheid door de beste ontwikkelingspraktijken toe te passen.


