By: John Häggkvist
2013-11-19
Micro Service Architechture
Som systemutvecklare har jag länge intresserat mig för Clean Code, arkitektur och olika sätt att strukturera kod. Jag har tidigare tittat en del på Actor-modellen, mer specifikt i Akka, och gillat tankesätten. Något jag funderat på den senaste tiden är Micro Service Architecture, ett sätt att komma bort från stora, otympliga och svårrörliga monoliter. Jag har på senare haft möjlighet att sätta upp och resonera kring arkitektur med små tjänster, och tänkte att jag skulle dela med mig av mina lärdomar.
Den första frågan man kan ställa sig är självklart; vad är Micro Service Architecture, och varför ska jag bry mig om det?
Något som man ofta stöter på som utvecklare är Monoliten. En stor koloss av kod, där allt ifrån frontend, backend, administrationsverktyg och batch-jobb bakas ihop. Väldigt ofta börjar olika delar av koden bero på andra delar av koden, och när man minst anar det så sitter man där med batch-jobb som av någon outgrundlig anledning beror på delar av frontend-koden. Har du någon gång suttit och försökt mocka bort beroenden för ett test med grundinställningen “Hur svårt kan det vara?”, men funnit dig själv timmar senare i en helt annan del av kodbasen frågandes hur du kom dit? Då förstår du precis vilken typ av system jag menar.
Stora system som ansvarar för en mängd funktionalitet blir krångliga. Mer kod och större domän att sätta sig in i är en stor tröghet för en utvecklare. Ju fler saker man måste hålla i huvudet samtidigt när man resonerar kring en förändring i koden destå mer riskfyllt kommer det kännas. Med bra struktur på sina klasser och moduler kommer man långt, men det finns ändå problematik man kan råka ut för.
Exempel på en applikation där man säljer böcker.
Jag har sett kodbaser där en deploy av en frontend-fix i administrationsverktyget kräver att man tar ner hela den publika webben. Det är inte ovanligt att en stor refaktorisering av PDF-genereringskoden potentiellt kan slå ut betalflöden. Micro Services tar tankesätten om moduler tagit ett steg ytterligare, och lyfter ut funktionalitet i egna små applikationer. Olika services blir byggblock och pusselbitar i din arkitektur.
Hur stor en service ska vara beror lite på vem man frågar, men den gränsen jag själv fastnat för är när man försöker bryta ut delar i logiska stycken, kopplade till domänen de arbetar i. Jag brukar försöka göra tjänsterna så små som möjligt, utan att det ska bli för omständigt att handskas med dem. Tjänster exponerar funktionalitet som är vettig och efterfrågad i systemet, exempel på detta kan varaSkapa kund, Köp bok, Ta fram alla köp för en kund. Jag själv förespråkar att varje tjänst ska ha kontroll på sin egen databas, och att ingen annan tjänst direkt ska använda/manipulera data utan att gå genom tjänstens gränssnitt. Med en sådan inställning blir det därför konstigt att dela upp Kund-tjänsten till mindre bitar i form av SkapaKund-tjänst och ListaKunder-tjänst, då de är väldigt intimt beroende av varandras data.
Ett exempel på samma tjänst byggt med Micro Service-tänk. Alla tjänster kommunicerar sinsemellan.
En av de absolut största fördelarna som jag stött på med den här typen av arkitektur, är att olika delar av ens system, som egentligen inte är beroende av varandra, kan leva var för sig. Att två delar av systemet kan leva var för sig innebär också att de kan dö var för sig. Det här innebär att bara man skriver sina tjänster på bra sätt, så kommer du till exempel kunna leverera alla böcker till de kunder som betalat, trots att betaltjänsten är nere. Oavsett om det är en deploy, en bugg eller ett planerat driftstopp så kommer den här typen av graceful degradation att öka den sammanlagda kvaliteten på din applikation.
Ett av de större besluten man behöver ta när man bygger en arkitektur kring små tjänster är hur tjänsterna ska kommunicera sinsemellan. Det finns många olika smaker, allt från exponerade REST-apier bakom lastbalanserare, centraliserade event-köer, Actors, Pub/Sub och broadcasting. Något som intresserar mig väldigt mycket är asynkrona event-köer. Jag tror att det passar Micro Services väldigt bra, och känns som en bra väg att utforska. Med det sagt kan dock vara svårt att bygga vidare på befintlig arkitektur om man tidigare inte haft det tankesättet, och kanske lämpar sig bättre för nya projekt. Det finns också en hel del utmaningar kring att skriva asynkrona flöden. Väljer man istället anrop över REST behöver man fundera på hur tjänster får reda på varandra och vad som ska hända om en tjänst ligger nere.
Jag kommer med stor sannolikhet återkomma med fler reflektioner och funderingar kring det här ämnet. Jag tänker just nu mycket på vikten med integrationstester, sätt att resonera kring asynkrona meddelanden och hur man undviker att bygga CRUD-tjänster som anropas av en tjänst som i princip ser ut som den gamla monoliten.
Är man nyfiken på ämnet så kan jag starkt rekommendera James Lewis föreläsning om Java – The Unix Way. När du sett videon och fått upp ögonen för konceptet så rekommenderar jag David Morgantinis blogg-serie om Micro Services där han tar upp för och nackdelar, och James Hughes inlägg om Micro Service Architecture.