Terug

Your Worst-case Serverless Scenario deel III: Het Onzichtbare Proces

Niels van Bree

6 min read

In deze derde en laatste aflevering van "Your Worst-case Serverless Scenario" zullen we het hebben over een vervelend 'onzichtbaar proces' van DynamoDB en kort ingaan op partitie ontwerpen en tabel indexen. We sluiten deze case af met een samenvatting van onze geleerde lessen. Als je de eerste twee delen van deze serie nog niet gelezen hebt, raden we je aan om ze te bekijken, aangezien dit artikel verder bouwt op de vorige artikelen.

Het Onzichtbare Proces

Last but not least, hebben we het probleem van de origin tabel die nog steeds problemen ondervindt nadat alles is opgeruimd. Meer specifiek, als je probeerde om meer items naar de tabel te schrijven, zelfs een dag later, zou je nog steeds time-out fouten krijgen. Lezen uit de tabel werkte echter prima. Het vreemde was dat je geen enkele activiteit in de metriek kon zien die aangaf dat schrijfverzoeken op dit moment werden gesmoord of dat er überhaupt een proces aan de gang was. Ook het aantal items in de tabel nam niet meer toe en auto scaling had de lees- en schrijfcapaciteiten teruggebracht tot hun normale capaciteiten. Zoals we al wisten van een ander geval, had dit te maken met het updaten van de index. Zodra je een item naar een tabel schrijft, zal dit item ook naar alle indexen van de tabel geschreven worden. Om dit te laten gebeuren, is een read op de basistabel en een write op de doelindexen nodig.

Onze auto scaling opties waren ingesteld op zowel lees- als schrijfcapaciteit afzonderlijk met dezelfde instellingen toegepast op alle Global Secondary Indexes (we hadden slechts één index). Dat betekende dat tijdens het massaal schrijven op de basistabel, de schrijfcapaciteiten van de basistabel en doelindex omhoog schoten, maar de leescapaciteit gelijk bleef. Met andere woorden: de items konden aanvankelijk naar de basistabel worden geschreven, maar daarna merkte de index dat hij het niet kon bijbenen, omdat, hoewel de schrijfcapaciteit van de index was opgeschaald, de leescapaciteit van de basistabel te laag was. Om het nog erger te maken, bleek de opgeschaalde schrijfcapaciteit ook onvoldoende te zijn, omdat de partitiesleutel van de index zeer slecht gekozen was. In dit specifieke geval hadden alle geschreven items op de basistabel verschillende partitiesleutelwaarden, maar dezelfde partitiesleutelwaarde op de index, wat in ons geval 56 miljoen items waren! Volgens de officiële AWS documentatie over het ontwerpen van partitiesleutels om je werk gelijkmatig te verdelen:

"Het partitiesleutelgedeelte van de primaire sleutel van een tabel bepaalt de logische partities waarin de gegevens van een tabel worden opgeslagen. Dit heeft op zijn beurt invloed op de onderliggende fysieke partities. De voorziene I/O-capaciteit voor de tabel wordt gelijk verdeeld over deze fysieke partities. Daarom kan een partitiesleutelontwerp dat I/O-verzoeken niet gelijkmatig verdeelt, 'hot' partities creëren die resulteren in throttling en inefficiënt gebruikmaken van uw I/O-capaciteit.

In het kort: een zeer slecht gekozen index' partitie sleutel en de scheiding van lees- en schrijfcapaciteit auto scaling leidden tot een index die simpelweg niet alle schrijfacties kon bijhouden die op de basistabel werden uitgevoerd. Het nare neveneffect was dat op de achtergrond de index nog steeds beetje bij beetje gevuld werd, maar er is geen enkele metric die je laat zien hoe het proces verloopt. Als iemand een idee heeft of en hoe we dit "onzichtbare proces" verder kunnen inspecteren en/of beïnvloeden, laat het ons weten in de commentaren, want dat zou zeer nuttig zijn om een beter begrip te krijgen van DynamoDB's achtergrond processen.

Onze beste oplossing om deze puinhoop op te ruimen was om een snapshot te nemen van de tabel van net voor dit alles begon en de tabel in die toestand te herstellen.

De lessen die we hebben geleerd

Hoewel wij nogal wat problemen hebben ondervonden toen dit alles gebeurde, was het ook het perfecte geval om van te leren. Ik denk dat het goed is deze zaak af te sluiten met een opsomming van enkele van de belangrijkste dingen die we ervan hebben geleerd.

  • Kennis + ervaring is macht: Terugkijkend op alles wat hier misging, hadden sommige dingen te maken met een simpel gebrek aan kennis of ervaring met sommige van de innerlijke werkingen van verschillende AWS-services, zoals de retry-poging van asynchrone Lambda-invocaties en het 'onzichtbare proces' van een DynamoDB-tabel. We merken dat hoe meer ervaren we zijn, hoe minder onaangename verrassingen we ervaren. Toch is het bijhouden en dubbel checken van de AWS documentatie noodzakelijk als we er bovenop willen blijven zitten.
  • Vermijd Lambda ketens zoveel mogelijk: Als er ergens in de keten iets misgaat, kunnen de gevolgen catastrofaal zijn. Wanneer we dit patroon weer nodig denken te hebben, moeten we overwegen de architectuur opnieuw te ontwerpen.
  • Gebruik de hulpmiddelen die je worden aangereikt: In aanvulling op het punt hierboven, bijvoorbeeld, het gebruik maken van Lambda's maximale uitvoeringstijd loste het probleem van het nodig hebben van een keten al op. Plus, zelfs als er meer executies nodig waren geweest, zou de keten een stuk kleiner zijn geweest en niet zoveel problemen hebben veroorzaakt.
  • Betere foutafhandeling + logging: Tests zijn er om voorziene fouten te voorkomen, maar hoe zit het met onvoorziene fouten? Dit geval heeft ons weer eens laten zien dat een goede foutafhandeling de sleutel is. Waar fouten kunnen optreden, zorg ervoor dat er logica is die de fout opvangt, de verdere uitvoering stopt of wijzigt om meer fouten te voorkomen en logt naar een plaats waar we kunnen inspecteren wat er precies fout ging.
  • Denk beter na over het ontwerp van tabelpartities: Een slecht gekozen partitie ontwerp kan een bottleneck veroorzaken in je (DynamoDB) tabel. De volgende keer dat we een tabel opzetten, moeten we hier zeker rekening mee houden en best practices volgen, vooral op tabellen waar we verwachten dat er een grote hoeveelheid items zullen worden ingevoegd.

En met de grootste geleerde lessen samengevat, sluit deze zaak. We streven er naar om nooit meer problemen op zo'n grote schaal te ervaren en we hopen dat jij dat ook nooit hoeft te doen. Al met al is deze case rijk geweest aan leermomenten voor ons en maakt het ons betere Serverless ontwikkelaars op de lange termijn. We hopen dat je genoten hebt van de artikelen en als je nog vragen of opmerkingen hebt, voel je vrij om ze te stellen.