Blogg

    • Så byggde vi ett socialt nätverk för sport med microservices, Event sourcing och CQRS

    Sandeep Rajoria, technical architect

    Prestanda och skalbarhet – det var två viktiga krav när en kund gav oss förtroendet att bygga en ny plattform för ett socialt nätverk inom sportvärlden. I denna bloggpost förklarar vår tekniske arkitekt Sandeep Rajoria hur vi skapade arkitekturen till denna vassa plattform.

    Eftersom microservices är utformade just för prestanda och skalbarhet, så valde vi att använda Event sourcing och CQRS för arkitekturen till den nya produkten.

    Syftet med det här blogginlägget är att dela med mig av insikter från implementationen och detaljer kring de huvudsakliga komponenterna i arkitekturen. Inlägget är dock inte avsett att vara en allmän guide till microservices.

    Okej – du har kanske noterat att jag har diskuterat Event sourcing, CQRS och microservices tillsammans. Det beror på att lösningen som vi byggde kombinerar viktiga koncept från alla tre. Här är en överblick av designen:

    Dessa är de viktigaste teknikerna som används i arkitekturen:

    1. Python-baserade Chalice-ramverket för AWS Lambda genom API Gateway
    2. Python-baserade Domovoi-ramverket för att trigga funktioner vid event
    3. DynamoDB och DynamoDB Streams
    4. SQS och SNS
    5. RDS
    6. ElastiCache
    7. PHP/Nginx-baserad setup på EC2
    8. Och dessutom gott om frontend-tekniker som jQuery, Handlebars, materialize-css etc.

     Nu ska vi prata lite om de huvudsakliga komponenterna i systemet.

     

    Event Store

    Event store är ryggraden i hela denna setup, och fungerar som en ledger där man bara kan lägga till, inte ändra befintlig information, för alla de ”event” som sker i systemet, sparade i kronologisk ordning. Trots att vår implementation av event store inte är en fullödig version innehåller den fortfarande alla de grundläggande bra grejerna från event store. Till exempel har vi ännu inte någon funktion för återuppspelning av events på plats, och vi behöver fortfarande fundera ut en standardprocess för datapopulering för en ny microservice.

    Men varje förändring i systemet loggas i vår event store när den godkänns av det berörda kommandot. De attribut som sparas här är event type, payload, vilken användare som initierade det, och en tidsstämpel – för att nämna några av det viktigaste.

    DynamoDB-tabellen med streams aktiverade agerar som vår event store, och vi har en Fan-out Lambda som triggas vid varje nytt event som sparas i DDB-tabellen.

    Fördelar: Lätt att installera, man kan använda gratisnivåerna på DynamoDB, du kan fysiskt kontrollera datan i raderna.

    Nackdelar: Kan bara trigga en eller max två lambda-funktioner, därför behövs en fan-out. Möjligheten att återställa markören (eller återuppspela event) är inte tillgänglig i ursprungsinstallationen.

    Andra alternativ: Kinesis Streams.

     

    Fan-out Lambda

    Fan-out lambdas uppgift är att sprida ut event till de microservices som prenumererar på (eller är intresserade av) specifika typer av event. Vi använde Python-baserade Domovoi-ramverket som agerar som stream trigger. Den enda uppgiften för denna funktion är att leda eventen vidare till annan lambda-funktionalitet.

    Fördelar: Lätt att installera, det är ett enda git-repo med all kod.

    Nackdelar: Den ansvarar för alltför många saker, kod som är specifik för olika microservices kan finnas i fanout-processen, ett väldigt högt antal event kan skapa fördröjning i processandet av event.

    Andra alternativ: Kinesis, eftersom det kan ha separata triggers på olika streams.

     

    CQRS Microservice

    Alla microservices vi bygger har en del för ”command and query”, där kommando-delen får sin request för post/put/delete direkt från UI/webbläsare/app, processar det, uppdaterar sin interna databas (och ett cachningslager eller en läsaroptimerad databas som NoSQL när det krävs) och publicerar alla event producerade av denna request.

    Läs-delen läser helt enkelt de lagrade eventen via en write-through cache närhelst det kommer en request av typen get.

    Vi använde Python-baserade Chalice-ramverket för alla microservices.

    Fördelar: Inkapsling av funktionalitet, läsoperationer är oberoende, snabbare och optimerade, enkelt att implementera.

    Nackdel: Extra kod och komplexitet, ett visst paradigmskifte från traditionell client-server-arkitektur, read and write-databaser kan vara osynkade, lambda cold-start var ett problem inledningsvis.

     

    EC2 server

    Det huvudsakliga uppdraget för en Ubuntu-baserad EC2 är att hosta frontend-applikationen med baserad på PHP, att ta hand om registrering och autentisering. Microservices använder JWT-baserad token för auktorisering, som genereras av backend-applikationen, sparas i webbläsarens lokala minne och skickas vidare vid varje förfrågan till microservices. Tillsammans med detta huvudsakliga arbete skickar den också event till event store från backend-systemet genom att skicka dessa event till en event-kö, som i sin tur notifierar lyssnare via SNS.

    Fördelar: Beprövade VPS-servers med massor av underbara verktyg för debugging.

    Nackdelar: Alltid på, resursutnyttjandet är inte det mest optimala.

    Andra alternativ: S3-baserad hostad UI genom Route53.

    Okej – då var det dags att runda av det här blogginlägget. Som ni märker har vi berört alla de stora delarna av arkitekturen, och förklarat lite om hur systemet fungerar som helhet. Den här arkitekturen hjälpte oss att uppnå önskad prestanda och skalbarhet, även om det finns utmaningar med att hantera denna applikation, Vi arbetar också på andra projekt i andra domäner där vi arbetar med att bryta upp en existerande monolit till flera microservices genom att använda samma mönster. Det visar sig vara ännu mer intressant, eftersom det har en helt egen uppsättning av oväntade problem.

    Sandeep Rajoria, teknisk arkitekt

  • Se video om hur det går till här