Dela via


Asynkron meddelandebaserad kommunikation

Dricks

Det här innehållet är ett utdrag från eBook, .NET Microservices Architecture for Containerized .NET Applications, tillgängligt på .NET Docs eller som en kostnadsfri nedladdningsbar PDF som kan läsas offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Asynkrona meddelanden och händelsedriven kommunikation är viktiga när ändringar sprids över flera mikrotjänster och deras relaterade domänmodeller. Som vi nämnde tidigare i diskussionen om mikrotjänster och begränsade kontexter (BCs) kan modeller (användare, kund, produkt, konto osv.) betyda olika saker för olika mikrotjänster eller BCs. Det innebär att när ändringar sker behöver du något sätt att stämma av ändringar mellan de olika modellerna. En lösning är slutlig konsekvens och händelsedriven kommunikation baserad på asynkrona meddelanden.

När du använder meddelanden kommunicerar processer genom att utbyta meddelanden asynkront. En klient skickar ett kommando eller en begäran till en tjänst genom att skicka ett meddelande till den. Om tjänsten behöver svara skickar den ett annat meddelande tillbaka till klienten. Eftersom det är en meddelandebaserad kommunikation förutsätter klienten att svaret inte tas emot omedelbart och att det kanske inte finns något svar alls.

Ett meddelande består av en rubrik (metadata som identifiering eller säkerhetsinformation) och en brödtext. Meddelanden skickas vanligtvis via asynkrona protokoll som AMQP.

Den föredragna infrastrukturen för den här typen av kommunikation i mikrotjänstcommunityn är en enkel meddelandekö som skiljer sig från de stora koordinatorer och orkestratorer som används i SOA. I en enkel meddelandekö är infrastrukturen vanligtvis "dum" och fungerar bara som meddelandekö med enkla implementeringar som RabbitMQ eller en skalbar servicebuss i molnet som Azure Service Bus. I det här scenariot lever de flesta av de "smarta" tänkandet fortfarande i slutpunkterna som producerar och konsumerar meddelanden , det vill: i mikrotjänsterna.

En annan regel som du bör försöka följa så mycket som möjligt är att endast använda asynkrona meddelanden mellan de interna tjänsterna och att använda synkron kommunikation (till exempel HTTP) endast från klientapparna till klientdelstjänsterna (API Gateways plus den första nivån av mikrotjänster).

Det finns två typer av asynkron meddelandekommunikation: meddelandebaserad kommunikation med enskild mottagare och meddelandebaserad kommunikation med flera mottagare. Följande avsnitt innehåller information om dem.

Meddelandebaserad kommunikation med en mottagare

Meddelandebaserad asynkron kommunikation med en enda mottagare innebär att det finns punkt-till-punkt-kommunikation som levererar ett meddelande till exakt en av de konsumenter som läser från kanalen och att meddelandet bearbetas bara en gång. Det finns dock särskilda situationer. I ett molnsystem som till exempel försöker återställa automatiskt från fel kan samma meddelande skickas på nytt flera gånger. På grund av nätverksfel eller andra fel måste klienten kunna försöka skicka meddelanden igen, och servern måste implementera en åtgärd för att vara idempotent för att bearbeta ett visst meddelande bara en gång.

Meddelandebaserad kommunikation med en mottagare passar särskilt bra för att skicka asynkrona kommandon från en mikrotjänst till en annan, vilket visas i bild 4–18 som illustrerar den här metoden.

När du börjar skicka meddelandebaserad kommunikation (antingen med kommandon eller händelser) bör du undvika att blanda meddelandebaserad kommunikation med synkron HTTP-kommunikation.

A single microservice receiving an asynchronous message

Bild 4-18. En enskild mikrotjänst som tar emot ett asynkront meddelande

När kommandona kommer från klientprogram kan de implementeras som HTTP-synkrona kommandon. Använd meddelandebaserade kommandon när du behöver högre skalbarhet eller när du redan befinner dig i en meddelandebaserad affärsprocess.

Meddelandebaserad kommunikation med flera mottagare

Som en mer flexibel metod kanske du också vill använda en publicerings-/prenumerationsmekanism så att kommunikationen från avsändaren blir tillgänglig för ytterligare prenumerantmikrotjänster eller externa program. Därför hjälper det dig att följa principen öppen/stängd i den sändande tjänsten. På så sätt kan ytterligare prenumeranter läggas till i framtiden utan att du behöver ändra avsändartjänsten.

När du använder en publicerings-/prenumerationskommunikation kanske du använder ett event bus-gränssnitt för att publicera händelser till alla prenumeranter.

Asynkron händelsedriven kommunikation

När du använder asynkron händelsedriven kommunikation publicerar en mikrotjänst en integrationshändelse när något händer inom domänen och en annan mikrotjänst måste vara medveten om den, till exempel en prisändring i en produktkatalogs mikrotjänst. Ytterligare mikrotjänster prenumererar på händelserna så att de kan ta emot dem asynkront. När det händer kan mottagarna uppdatera sina egna domänentiteter, vilket kan göra att fler integreringshändelser publiceras. Det här publicerings-/prenumerationssystemet utförs med hjälp av en implementering av en händelsebuss. Händelsebussen kan utformas som en abstraktion eller ett gränssnitt, med det API som behövs för att prenumerera eller avbryta prenumerationen på händelser och publicera händelser. Händelsebussen kan också ha en eller flera implementeringar baserat på alla mellanprocesser och meddelandeköer, till exempel en meddelandekö eller servicebuss som stöder asynkron kommunikation och en modell för publicering/prenumeration.

Om ett system använder slutlig konsekvens som drivs av integrationshändelser rekommenderar vi att den här metoden görs tydlig för slutanvändaren. Systemet bör inte använda en metod som efterliknar integrationshändelser, till exempel SignalR eller avsökningssystem från klienten. Slutanvändaren och företagsägaren måste uttryckligen anamma eventuell konsekvens i systemet och inse att företaget i många fall inte har några problem med den här metoden, så länge det är explicit. Den här metoden är viktig eftersom användarna kan förvänta sig att se vissa resultat omedelbart och den här aspekten kanske inte inträffar med slutlig konsekvens.

Som tidigare nämnts i avsnittet Utmaningar och lösningar för distribuerad datahantering kan du använda integreringshändelser för att implementera affärsuppgifter som omfattar flera mikrotjänster. Därför får du slutlig konsekvens mellan dessa tjänster. En så småningom konsekvent transaktion består av en samling distribuerade åtgärder. Vid varje åtgärd uppdaterar den relaterade mikrotjänsten en domänentitet och publicerar en annan integrationshändelse som genererar nästa åtgärd inom samma verksamhetsuppgift från slutpunkt till slutpunkt.

En viktig punkt är att du kanske vill kommunicera med flera mikrotjänster som prenumererar på samma händelse. För att göra det kan du använda publicera/prenumerera på meddelanden baserat på händelsedriven kommunikation, enligt bild 4–19. Den här publicerings-/prenumerationsmekanismen är inte exklusiv för mikrotjänstarkitekturen. Det liknar hur avgränsade kontexter i DDD ska kommunicera, eller hur du sprider uppdateringar från skrivdatabasen till läsdatabasen i CQRS-arkitekturmönstret (Command and Query Responsibility Segregation). Målet är att ha slutlig konsekvens mellan flera datakällor i ditt distribuerade system.

Diagram showing asynchronous event-driven communications.

Bild 4-19. Asynkron händelsedriven meddelandekommunikation

I asynkron händelsedriven kommunikation publicerar en mikrotjänst händelser till en händelsebuss och många mikrotjänster kan prenumerera på den för att få aviseringar och agera på den. Implementeringen avgör vilket protokoll som ska användas för händelsedriven, meddelandebaserad kommunikation. AMQP kan hjälpa till att uppnå tillförlitlig kökommunikation.

När du använder en händelsebuss kanske du vill använda en abstraktionsnivå (till exempel ett händelsebussgränssnitt) baserat på en relaterad implementering i klasser med kod som använder API:et från en meddelandekö som RabbitMQ eller en servicebuss som Azure Service Bus med Ämnen. Du kan också använda en servicebuss på högre nivå som NServiceBus, MassTransit eller Brighter för att artikulera din händelsebuss och publicera/prenumerera.

En anteckning om meddelandetekniker för produktionssystem

De meddelandetekniker som är tillgängliga för att implementera din abstrakta händelsebuss finns på olika nivåer. Till exempel ligger produkter som RabbitMQ (en meddelandekötransport) och Azure Service Bus på en lägre nivå än andra produkter som NServiceBus, MassTransit eller Brighter, som kan fungera ovanpå RabbitMQ och Azure Service Bus. Ditt val beror på hur många omfattande funktioner på programnivå och out-of-the-box-skalbarhet du behöver för ditt program. För att bara implementera en proof-of-concept-händelsebuss för din utvecklingsmiljö, som det gjordes i exemplet eShopOnContainers, kan det räcka med en enkel implementering ovanpå RabbitMQ som körs på en Docker-container.

För verksamhetskritiska system och produktionssystem som behöver hyperskalbarhet kanske du vill utvärdera Azure Service Bus. För abstraktioner på hög nivå och funktioner som gör det enklare att utveckla distribuerade program rekommenderar vi att du utvärderar andra kommersiella bussar och servicebussar med öppen källkod, till exempel NServiceBus, MassTransit och Brighter. Du kan naturligtvis skapa egna service bus-funktioner ovanpå tekniker på lägre nivå som RabbitMQ och Docker. Men det VVS-arbetet kan kosta för mycket för ett anpassat företagsprogram.

Publicera motståndskraftigt till händelsebussen

En utmaning när du implementerar en händelsedriven arkitektur över flera mikrotjänster är hur du atomiskt uppdaterar tillståndet i den ursprungliga mikrotjänsten samtidigt som den motståndskraftigt publicerar sin relaterade integrationshändelse i händelsebussen, på något sätt baserat på transaktioner. Följande är några sätt att utföra den här funktionen, även om det kan finnas ytterligare metoder också.

  • Använda en transaktionskö (DTC-baserad) som MSMQ. (Detta är dock en äldre metod.)

  • Använda utvinning av transaktionsloggar.

  • Med hjälp av ett fullständigt mönster för händelsekällor .

  • Med hjälp av utkorgsmönstret: en transaktionsdatabastabell som en meddelandekö som ska vara basen för en komponent för händelseskapare som skulle skapa händelsen och publicera den.

En mer fullständig beskrivning av utmaningarna i det här utrymmet, inklusive hur meddelanden med potentiellt felaktiga data kan publiceras, finns i Dataplattform för verksamhetskritiska arbetsbelastningar i Azure: Varje meddelande måste bearbetas.

Ytterligare ämnen att tänka på när du använder asynkron kommunikation är meddelande-idempotens och meddelandededuplicering. De här avsnitten beskrivs i avsnittet Implementera händelsebaserad kommunikation mellan mikrotjänster (integrationshändelser) senare i den här guiden.

Ytterligare resurser