Microservicearchitectuur
Een microservicearchitectuur bestaat uit een verzameling kleine, autonome services. Elke service staat op zichzelf en moet één bedrijfsmogelijkheid binnen een contextgrens implementeren. Een contextgrens is een natuurlijke deling binnen een bedrijf en biedt een expliciete grens waaruit een domeinmodel bestaat.

Wat zijn microservices?
Microservices zijn klein, onafhankelijk en losjes met elkaar verbonden. Een klein team van ontwikkelaars is voldoende om een service te schrijven en te onderhouden.
Elke service is een afzonderlijke codebasis, die kan worden beheerd door een klein ontwikkelteam.
Services kunnen onafhankelijk van elkaar worden geïmplementeerd. Een team kan een bestaande service bijwerken zonder dat hiervoor de hele toepassing opnieuw hoeft te worden gebouwd en geïmplementeerd.
Services zijn verantwoordelijk voor het persistent maken van hun eigen gegevens of externe status. Dit wijkt af van het traditionele model, waarin een afzonderlijke gegevenslaag de persistentie van gegevens afhandelt.
Services communiceren met elkaar via goed gedefinieerde API's. Interne implementatiegegevens van een service zijn onzichtbaar voor andere services.
Ondersteunt polyglot-programmering. Services hoeven bijvoorbeeld niet dezelfde technologiestack, bibliotheken of frameworks te delen.
Een typische microservicearchitectuur bevat enkele andere componenten, naast de services zelf:
Beheer/indeling. Deze component is verantwoordelijk voor het plaatsen van services op knooppunten, het identificeren van fouten, het herverdelen van services over knooppunten, enzovoort. Dit onderdeel is doorgaans een kant-en-klare technologie zoals Kubernetes, niet iets dat op maat wordt gebouwd.
API-gateway. De API-gateway is het toegangspunt voor clients. Een client roept services niet direct aan, maar verstuurt een aanroep naar de API-gateway, die de aanroep doorstuurt naar de juiste services in de back-end.
Enkele voordelen van het gebruik van een API-gateway zijn:
Clients worden losgekoppeld van services. Services kunnen een nieuwe versie krijgen of worden geherstructureerd zonder dat alle clients hoeven te worden bijgewerkt.
Services kunnen berichtenprotocollen gebruiken die niet webvriendelijk zijn, zoals AMQP.
De API-gateway kan andere algemene functies uitvoeren zoals verificatie, logboekregistratie, SSL-beëindiging en taakverdeling.
Out-of-the-box-beleid, zoals voor beperking, caching, transformatie of validatie.
Voordelen
Agility. Omdat microservices onafhankelijk van elkaar worden geïmplementeerd, is het eenvoudiger om het oplossen van problemen en het uitgeven van nieuwe releases te beheren. U kunt een service bijwerken zonder dat u de hele toepassing opnieuw hoeft te implementeren en u kunt een update terugdraaien als er iets misgaat. Wanneer echter een bepaald deel van een traditionele toepassing een fout bevat, dan wordt hierdoor vaak het volledige vrijgaveproces geblokkeerd. De introductie van nieuwe functies kunnen worden vertraagd totdat de oplossing voor het probleem is geïntegreerd, getest en gepubliceerd.
Kleine, doelgerichte teams. Een microservice moet zo klein zijn dat één enkel functieteam deze kan bouwen, testen en implementeren. Inzet van kleinere teams stimuleert meer flexibiliteit. Grote teams zijn vaak minder productief: de communicatie verloopt langzamer, de managementoverhead neemt toe en de flexibiliteit juist af.
Kleine codebasis. In een monolithische toepassing bestaat de neiging dat codeafhankelijkheden na een periode met elkaar worden verward. Als u een nieuwe functie toevoegt, moet u op veel plaatsen code raken. Door code of gegevensarchieven niet de delen, bestaat er binnen een microservicearchitectuur een minimum aan afhankelijkheden, waardoor het gemakkelijker wordt om nieuwe functies toe te voegen.
Een combinatie van technologieën. Teams kunnen de technologie kiezen die het beste past bij de service waar ze aan werken en de combinatie van technologiepakketten gebruiken die zij het meest geschikt achten.
Foutisolatie. Als een afzonderlijke microservice uitvalt, verstoort dat niet de werking van de hele toepassing, zolang er upstream microservices zijn die zijn ontworpen om fouten op de juiste manier af te handelen (bijvoorbeeld door het circuit te onderbreken).
Schaalbaarheid. De schaal van services kan onafhankelijk worden aangepast, dus u kunt subsystemen uitschalen waarvoor meer resources nodig zijn, zonder dat u de volledige toepassing hoeft uit te schalen. Door een orchestrator als Kubernetes of Service Fabric te gebruiken, kunt u microservices ook met een hogere dichtheid op één host plaatsen, waardoor resources efficiënter kunnen worden benut.
Gegevensisolatie. Het is veel eenvoudiger om schema-updates uit te voeren, aangezien het slechts één microservice betreft. Bij monolithische toepassingen kan het uitvoeren van schema-updates heel lastig zijn, omdat verschillende onderdelen van de toepassing mogelijk van dezelfde gegevens gebruikmaken. Hierdoor kan het aanbrengen van wijzigingen in het schema riskant zijn.
Uitdagingen
Er staat wel iets tegenover de voordelen van microservices. Hier volgen enkele uitdagingen waarmee u rekening moet houden voordat u kiest voor een microservicearchitectuur.
Complexiteit. Een microservicetoepassing bevat meer bewegende onderdelen dan de equivalente monolithische toepassing. Elke service is eenvoudiger, maar het systeem als geheel is complexer.
Ontwikkeling en testen. Het schrijven van een kleine service die afhankelijk is van andere afhankelijke services, vereist een andere benadering dan het schrijven van een traditionele monolithische of gelaagde toepassing. Bestaande hulpprogramma's zijn niet altijd ontworpen voor gebruik met serviceafhankelijkheden. Herstructurering buiten servicegrenzen kan lastig zijn. Het testen van serviceafhankelijkheden is ook een uitdaging, met name wanneer de toepassing zich snel ontwikkelt.
Gebrek aan governance. Een gedecentraliseerde aanpak voor het bouwen van microservices heeft zo zijn voordelen, maar kan ook problemen veroorzaken. De kans bestaat dat er uiteindelijk zo veel verschillende talen en frameworks zijn dat het moeilijk wordt om de toepassing te onderhouden. Het kan daarom zinvol zijn om enkele projectbrede standaarden vast te leggen, zonder de flexibiliteit van teams te veel te beperken. Dit is vooral een goed idee voor algemene functionaliteit zoals logboekregistratie.
Netwerkcongestie en latentie. Het gebruik van veel kleine, gespecialiseerde services kan resulteren in meer communicatie tussen deze services. Als de keten van serviceafhankelijkheden te lang wordt (service A roept service B aan, die C aanroept..), kan de extra latentie ook een probleem worden. U moet daarom zorgvuldig te werk gaan bij het ontwerpen van API's. Vermijd overbodige API's, denk na over serialisatie-indelingen en zoek naar locaties om asynchrone communicatiepatronen te gebruiken, zoals load leveling op basis van wachtrijen.
Gegevensintegriteit. Aangezien elke microservice zelf verantwoordelijk is voor de persistentie van gegevens, Daarom kan gegevensconsistentie een uitdaging zijn. Kies waar mogelijk voor uiteindelijke consistentie.
Beheer. U hebt een goed ontwikkelde DevOps-cultuur nodig om succesvol te kunnen werken met microservices. Gecorreleerde logboekregistratie tussen services kan lastig zijn. Doorgaans moet logboekregistratie zo zijn geconfigureerd dat meerdere serviceaanroepen voor één gebruikersbewerking worden gecorreleerd.
Versiebeheer. Updates van een service mogen geen gevolgen hebben voor de beschikbaarheid van afhankelijke services. Het is mogelijk dat op een bepaald moment meerdere services tegelijk worden bijgewerkt, dus zonder een zorgvuldig ontwerp kunnen er al snel problemen ontstaan met achterwaartse of voorwaartse compatibiliteit.
Vaardighedenset. Microservices zijn zeer sterk gedistribueerde systemen. Evalueer zorgvuldig of het team beschikt over de vaardigheden en ervaring om succesvol te zijn.
Aanbevolen procedures
Modelleer services rondom het bedrijfsdomein.
Decentraliseer alles. Afzonderlijke teams zijn verantwoordelijk voor het ontwerpen en ontwikkelen van services. Vermijd het delen van code of gegevensschema's.
Opslag van gegevens moet exclusief zijn voor de service die eigenaar is van de gegevens. Gebruik het beste type opslag voor elke service en elk gegevenstype.
Services communiceren via goed ontworpen API's. Voorkom het weglekken van implementatiegegevens. API's moeten het domein modelleren, niet de interne implementatie van de service.
Voorkom koppeling tussen services. Oorzaken van koppeling zijn gedeelde databaseschema's en starre communicatieprotocollen.
Offload algemene problemen, zoals verificatie en SSL-beëindiging, naar de gateway.
Houd domeinkennis buiten de gateway. De gateway moet clientaanvragen verwerken en doorsturen zonder dat hierbij kennis van de bedrijfsregels of domeinlogica wordt gebruikt. Anders wordt de gateway namelijk een afhankelijkheid, wat kan leiden tot koppeling tussen services.
Services moeten losjes zijn gekoppeld en een grote functionele samenhang hebben. Functies die zijn zeer waarschijnlijk gezamenlijk zullen worden gewijzigd, moeten samen worden verpakt en tegelijk worden geïmplementeerd. Als ze zich in afzonderlijke services bevinden, worden die services uiteindelijk nauw verweven, omdat een wijziging in de ene service betekent dat de andere service ook moet worden bijgewerkt. Een te intensieve communicatie tussen twee services kan een symptoom zijn van hechte koppeling en lage samenhang.
Isoleer fouten. Gebruik tolerantiestrategieën om te voorkomen dat fouten in een service een golfeffect hebben. Zie Tolerantiepatronen en Betrouwbare toepassingen ontwerpen.
Volgende stappen
Zie Microservices ontwerpen, bouwen en beheren in Azure voor uitgebreide richtlijnen voor het bouwen van een microservicearchitectuur in Azure.