Microservice-arkitektur... jamen er det ikke bare at tegne noget som ligner en distribueret monolit fragmenteret i henhold til domæner og med en kommunikationsmodel baseret på REST-api principper?

Ressourcer:

  • Bog: Microservices Security in Action (2020) af Prabath Siriwardena og Nuwan Dias

Til at starte med gik jeg bare i kast med at kode microservicesene som jeg ville have kodet forskellige komponenter i en distribueret monolit. Jeg tænkte om dem som jeg ville tænke over de forskellige komponenter i en distribueret monolit, og afgrænse servicene efter ansvar. UserService ville stå for alt user-relateret (Authentication, authorization og CRUD-funktioner), som jeg havde gjort det i mit forrige projekt (DogRallyManager) vha. Entity Framework og Microsoft Identity. ActivityDiaryService skulle stå for alt relateret i fht. indlæg, osv. osv.

Kommunikationen skulle foregå fra frontenden og vha. http-requests til diverse microservices skulle komponenterne på frontenden fodres med data.

Jeg kodet og jeg kodet. Det gik jo godt. Der var forbindelse og det gik egentlig ret intuitivt. Så var det at min produktvejleder sagde, at det var godt at tænke sikkerhed ind fra starten. Jaja, sikkerhed, end-to-end-point kryptering (kryds af i HTTPS-support i ASP NET CORE ved kreering af hver microservice), snildt, overskueligt. Det tænkte jeg til at starte med. Så var det, at jeg tog til et af 'Ambars' kursuser i MicroService arkitektur. Jeg ville ønske jeg kunne linke til det her, men det er umuligt at opsnuse vha. Google. Det poppede op som en reklame på YouTube.
Her er et link til selve Ambar-firmaet: https://ambar.cloud/about-us
Jeg skrev mig op, det var af tre timers længde hver dag i en uge. Og her fik jeg sømfast nogle principper i fht. microservices, som senere blev hamret godt i ved videre læsning af bogen Microservices Security in Action.

Hvis jeg gik med min første kommunikationsmodel, hvor frontend kommunikerer direkte med microservices, ville det kræve, at der lå en autentificering af sessionscookien i hver microservice. Her begyndte det at gå op for mig, at det var lidt mere komplekst end så, at lave et program med microservice-arkitektur. Ihvertfald hvis man ønskede at udvikle en løsning som minimerer typiske problemer og faldgruber for denne måde at bygge software på.

For jeg kunne godt se at jeg synes det blev noget rod, hvis jeg med hvert request skulle forbi UserService og få autentificeret sessionscookien, eller implementere Microsoft Identity i hver microservice. Jeg synes det gav noget unødvendig overhead at skulle forbi UserService med hvert request, og jeg synes at jeg begyndte at bevæge mig udover ansvarsuddeligeringen hvis jeg implementerede Microsoft Identity i hver service. Og skulle alle microservices så have adgang til samme databasebase..... Og hvordan i forhold til skalering.... hvis jeg forventede en masse traffik og skulle skalere, og gik med, at alle requests skulle igennem UserService, så ville jeg ved skalering af denne også skalere på en tung service i form af al den kodning og de funktioner CRUD-funktioner, som også ville koste ressourser og overhead fordi de implicit lå i UserService, som jeg tænkte skulle stå for autentificering af requests.

Jeg kunne godt fornemme at jeg blev nødt til at stille mig spørgsmålet igen: Hvad er UserService's ansvar egentlig?

Og så slog det mig at jeg stadig tænkte for meget i monolitisk arkitektur omkring mine microservices. UserService skal bare stå for CRUD-funktioner og Identity tabeller (såsom også claims), og autentificering og authorization skulle uddeligeres til sine egne services.

Af Ambar's kursus fremgik det at et konventionelt arkitektur mønster indenfor microservices er at sætte en API-gateway foran sine microservices, hvor igennem alle requests fra frontenden går. En Gateway... okay... Hvad er det? Hvilken skal jeg vælge? Hvordan og hvorledes...
Og hvorfor er det gateways er sådan et velkendt mønster? Svar fik jeg sådan nogenlunde, men det tog noget tankeæltning at komme frem til min egen forståelse af hvilke kompleksiteter det gør nemmere i en microservice-arkitektur. En gateway kan screene requests (datavalidering, autentificering og autorisering), load-balance og hvad jeg i udgangspunktet fandt mest nyttig: strømline flowet fra frontend til backend.

Det viste sig jo hurtigt når vi skulle lave hooks fra frontenden til den tilsvarende backend microservice, at det kunne involvere en noget omsonst vedvarende kalibrering af
Jamen hvilket url har den pågældende microservice?
og jeg kunne godt se det smarte i bare at kunne fortælle mine frontenders: Når i skal lave requests til backenden, så gør i det altid til dette url: e.g. https://localhost:8000 med en et resurse kald som f.eks. login, og så kunne jeg selv stå for at dirigere korrekt fra gatewayen og til pågældende microservice, og udsætte requesten for validering og autentificering osv. På den måde skulle frontenderne ikke konstant opdateres i fht. hvilket endpoint de skulle have fat i. Vi kunne bare blive enige om et resursenavn /resursenavn og så forblev "koblingen" i mellem frontend og backend løs i termonologi og addressering af ressurse på netværket. Og dertil kunne jeg vælge at konfigurere mine microservices til kun at acceptere requests fra gatewayen og min rabbitmq microservice (hvori jeg havde valgt at foretage kommunikationen af årsager som jeg udredder i en post om valg kommunikationsmodel for microservices )
Jeg kunne fortsætte med at skrive om gatewayen og hvorfor den er sej, men det vælger jeg at gøre i en anden post om mit valg af gateway.

Jeg traf et arkitektur-valg af sikkerhedsmæssige hensyn, skaleringsmæssigehensyn, quality-of-life-hensyn og for at danne en centraliseret indgang for alle requests.
Selvfølgelig skulle vi have en API-gateway . Men skulle den også stå for autentificering og autorisering? Fortsættelse følger....




Opdateret: