Introduktion till Service Fabric Reliable Actors

Reliable Actors är ett Service Fabric-programramverk baserat på mönstret Virtuell aktör . Reliable Actors-API:et tillhandahåller en enkeltrådad programmeringsmodell som bygger på skalbarhets- och tillförlitlighetsgarantierna som tillhandahålls av Service Fabric.

Vad är skådespelare?

En aktör är en isolerad, oberoende enhet för beräkning och tillstånd med en trådad körning. Aktörsmönstret är en beräkningsmodell för samtidiga eller distribuerade system där ett stort antal av dessa aktörer kan köras samtidigt och oberoende av varandra. Aktörer kan kommunicera med varandra och de kan skapa fler aktörer.

När reliable actors ska användas

Service Fabric Reliable Actors är en implementering av aktörens designmönster. Precis som med alla mönster för programvarudesign fattas beslutet om ett specifikt mönster ska användas baserat på om ett programvarudesignproblem passar mönstret eller inte.

Även om aktörens designmönster kan passa bra för ett antal problem och scenarier med distribuerade system, måste du noggrant överväga begränsningarna i mönstret och ramverket som implementerar det. Som allmän vägledning bör du överväga aktörsmönstret för att modellera ditt problem eller scenario om:

  • Ditt problemutrymme omfattar ett stort antal (tusentals eller fler) små, oberoende och isolerade enheter av tillstånd och logik.
  • Du vill arbeta med entrådade objekt som inte kräver betydande interaktion från externa komponenter, inklusive frågetillstånd för en uppsättning aktörer.
  • Dina aktörsinstanser blockerar inte uppringare med oförutsägbara fördröjningar genom att utfärda I/O-åtgärder.

Aktörer i Service Fabric

I Service Fabric implementeras aktörer i ramverket Reliable Actors: Ett aktörsmönsterbaserat programramverk som bygger på Service Fabric Reliable Services. Varje Reliable Actor-tjänst som du skriver är faktiskt en partitionerad, tillståndskänslig Reliable Service.

Varje aktör definieras som en instans av en aktörstyp, identisk med hur ett .NET-objekt är en instans av en .NET-typ. Det kan till exempel finnas en aktörstyp som implementerar funktionen i en kalkylator och det kan finnas många aktörer av den typen som distribueras på olika noder i ett kluster. Varje sådan aktör identifieras unikt av ett aktörs-ID.

Skådespelarens livslängd

Service Fabric-aktörer är virtuella, vilket innebär att deras livslängd inte är kopplad till deras minnesinterna representation. Därför behöver de inte skapas eller förstöras uttryckligen. Reliable Actors-körningen aktiverar automatiskt en aktör första gången den tar emot en begäran om det aktörs-ID:t. Om en aktör inte används under en viss tidsperiod samlar Reliable Actors-skräpmiljön in det minnesinterna objektet. Det kommer också att upprätthålla kunskap om aktörens existens om den behöver återaktiveras senare. Mer information finns i Aktörslivscykel och skräpinsamling.

Den här livslängdsabstraktionen för den virtuella aktören medför vissa förbehåll som ett resultat av modellen för den virtuella aktören, och i själva verket avviker Reliable Actors-implementeringen ibland från den här modellen.

  • En aktör aktiveras automatiskt (vilket gör att ett aktörsobjekt skapas) första gången ett meddelande skickas till dess aktörs-ID. Efter en viss tidsperiod samlas aktörsobjektet in. I framtiden, med hjälp av aktörs-ID:t igen, skapas ett nytt aktörsobjekt. En aktörs tillstånd överlever objektets livslängd när det lagras i tillståndshanteraren.
  • Om du anropar en aktörsmetod för ett aktörs-ID aktiveras den aktören. Av den anledningen har aktörstyper sin konstruktor som anropas implicit av körningen. Klientkoden kan därför inte skicka parametrar till aktörstypens konstruktor, även om parametrar kan skickas till aktörens konstruktor av själva tjänsten. Resultatet är att aktörer kan konstrueras i ett delvis initierat tillstånd när andra metoder anropas, om aktören kräver initieringsparametrar från klienten. Det finns ingen enda startpunkt för aktivering av en aktör från klienten.
  • Även om Reliable Actors implicit skapar aktörsobjekt; du har möjlighet att uttryckligen ta bort en aktör och dess tillstånd.

Distribution och redundans

För att ge skalbarhet och tillförlitlighet distribuerar Service Fabric aktörer i hela klustret och migrerar dem automatiskt från misslyckade noder till felfria noder efter behov. Det här är en abstraktion över en partitionerad, tillståndskänslig Reliable Service. Distribution, skalbarhet, tillförlitlighet och automatisk redundans tillhandahålls på grund av att aktörer körs i en tillståndskänslig Reliable Service som kallas aktörstjänsten.

Aktörer distribueras över partitionerna i aktörstjänsten och dessa partitioner distribueras över noderna i ett Service Fabric-kluster. Varje tjänstpartition innehåller en uppsättning aktörer. Service Fabric hanterar distribution och redundans för tjänstpartitionerna.

En aktörstjänst med nio partitioner distribuerade till tre noder med standardplaceringen av aktörspartitionen skulle till exempel distribueras på följande sätt:

Reliable Actors-distribution

Actor Framework hanterar partitionsschema och nyckelintervallinställningar åt dig. Detta förenklar vissa val men har också vissa överväganden:

  • Med Reliable Services kan du välja ett partitioneringsschema, nyckelintervall (när du använder ett intervallpartitioneringsschema) och antal partitioner. Reliable Actors är begränsat till intervallpartitioneringsschemat (det enhetliga Int64-schemat) och kräver att du använder hela Int64-nyckelintervallet.
  • Som standard placeras aktörer slumpmässigt i partitioner vilket resulterar i en enhetlig fördelning.
  • Eftersom aktörer placeras slumpmässigt bör det förväntas att aktörsåtgärder alltid kräver nätverkskommunikation, inklusive serialisering och deserialisering av metodanropsdata, vilket medför svarstid och omkostnader.
  • I avancerade scenarier är det möjligt att styra aktörens partitionsplacering med hjälp av Int64-aktörs-ID:t som mappar till specifika partitioner. Detta kan dock resultera i en obalanserad fördelning av aktörer mellan partitioner.

Mer information om hur aktörstjänster partitioneras finns i partitioneringsbegrepp för aktörer.

Aktörskommunikation

Aktörsinteraktioner definieras i ett gränssnitt som delas av aktören som implementerar gränssnittet och klienten som hämtar en proxy till en aktör via samma gränssnitt. Eftersom det här gränssnittet används för att anropa aktörsmetoder asynkront måste varje metod i gränssnittet vara Uppgiftsretur.

Metodanrop och deras svar resulterar i slutänden i nätverksbegäranden i klustret, så argumenten och resultattyperna för de uppgifter som de returnerar måste serialiseras av plattformen. I synnerhet måste de vara serialiserbara för datakontrakt.

Aktörsproxyn

Reliable Actors-klient-API:et tillhandahåller kommunikation mellan en aktörsinstans och en aktörsklient. För att kommunicera med en aktör skapar en klient ett aktörsproxyobjekt som implementerar aktörsgränssnittet. Klienten interagerar med aktören genom att anropa metoder på proxyobjektet. Aktörsproxyn kan användas för kommunikation mellan klienter och skådespelare och skådespelare.

// Create a randomly distributed actor ID
ActorId actorId = ActorId.CreateRandom();

// This only creates a proxy object, it does not activate an actor or invoke any methods yet.
IMyActor myActor = ActorProxy.Create<IMyActor>(actorId, new Uri("fabric:/MyApp/MyActorService"));

// This will invoke a method on the actor. If an actor with the given ID does not exist, it will be activated by this method call.
await myActor.DoWorkAsync();
// Create actor ID with some name
ActorId actorId = new ActorId("Actor1");

// This only creates a proxy object, it does not activate an actor or invoke any methods yet.
MyActor myActor = ActorProxyBase.create(actorId, new URI("fabric:/MyApp/MyActorService"), MyActor.class);

// This will invoke a method on the actor. If an actor with the given ID does not exist, it will be activated by this method call.
myActor.DoWorkAsync().get();

Observera att de två informationsdelarna som används för att skapa aktörsproxyobjektet är aktörs-ID:t och programnamnet. Aktörs-ID:t identifierar aktören unikt, medan programnamnet identifierar Service Fabric-programmet där aktören distribueras.

ActorProxyKlassen (C#) / ActorProxyBase(Java) på klientsidan utför den matchning som krävs för att hitta aktören efter ID och öppna en kommunikationskanal med den. Den försöker också hitta aktören vid kommunikationsfel och redundans. Därför har meddelandeleverans följande egenskaper:

  • Meddelandeleverans är det bästa sättet.
  • Aktörer kan ta emot duplicerade meddelanden från samma klient.

Samtidighet

Reliable Actors-körningen tillhandahåller en enkel turbaserad åtkomstmodell för åtkomst till aktörsmetoder. Det innebär att inte mer än en tråd kan vara aktiv i ett aktörsobjekts kod när som helst. Turbaserad åtkomst förenklar avsevärt samtidiga system eftersom det inte finns något behov av synkroniseringsmekanismer för dataåtkomst. Det innebär också att system måste utformas med särskilda överväganden för den enskilda trådade åtkomsten för varje aktörsinstans.

  • En enskild aktörsinstans kan inte bearbeta mer än en begäran i taget. En aktörsinstans kan orsaka flaskhalsar i dataflödet om den förväntas hantera samtidiga begäranden.
  • Aktörer kan låsa upp varandra om det finns en cirkulär begäran mellan två aktörer medan en extern begäran görs till en av aktörerna samtidigt. Aktörskörningen överskrider automatiskt tidsgränsen för aktörsanrop och utlöser ett undantag för anroparen för att avbryta eventuella dödlägen.

Reliable Actors-kommunikation

Turbaserad åtkomst

En tur består av en fullständig körning av en aktörsmetod som svar på en begäran från andra aktörer eller klienter, eller en fullständig körning av ett timer-/påminnelseanrop . Även om dessa metoder och återanrop är asynkrona, interleaves inte Actors-körningen dem. En sväng måste vara helt klar innan en ny sväng tillåts. Med andra ord måste en aktörsmetod eller timer/påminnelse-motringning som körs för närvarande vara helt klar innan ett nytt anrop till en metod eller återanrop tillåts. En metod eller återanrop anses ha slutförts om körningen har returnerats från metoden eller återanropet och uppgiften som returneras av metoden eller återanropet har slutförts. Det är värt att betona att turbaserad samtidighet respekteras även mellan olika metoder, timers och återanrop.

Actors-körningen framtvingar turbaserad samtidighet genom att hämta ett lås per aktör i början av en sväng och släppa låset i slutet av svängen. Därför tillämpas turbaserad samtidighet per aktör och inte mellan olika aktörer. Aktörsmetoder och timer-/påminnelseåteranrop kan köras samtidigt för olika aktörers räkning.

I följande exempel visas ovanstående begrepp. Överväg en aktörstyp som implementerar två asynkrona metoder (till exempel Metod1 och Metod2), en timer och en påminnelse. Diagrammet nedan visar ett exempel på en tidslinje för körning av dessa metoder och återanrop för två aktörer (ActorId1 och ActorId2) som tillhör den här aktörstypen.

Reliable Actors runtime turbaserad samtidighet och åtkomst

Det här diagrammet följer dessa konventioner:

  • Varje lodrät linje visar det logiska flödet för körning av en metod eller ett återanrop för en viss aktörs räkning.
  • Händelserna som markeras på varje lodrät linje sker i kronologisk ordning, med nyare händelser som inträffar under äldre.
  • Olika färger används för tidslinjer som motsvarar olika aktörer.
  • Markeringen används för att ange hur länge låset per aktör ska hållas för en metod eller återanrop.

Några viktiga saker att tänka på:

  • Medan Method1 körs för ActorId2 som svar på klientbegäran xyz789, kommer en annan klientbegäran (abc123) som också kräver att Method1 körs av ActorId2. Den andra körningen av Method1 startar dock inte förrän den tidigare körningen har slutförts. På samma sätt utlöses en påminnelse som registrerats av ActorId2 medan Method1 körs som svar på klientbegäran xyz789. Återanropet av påminnelsen körs endast när båda körningarna av Method1 har slutförts. Allt detta beror på att turbaserad samtidighet tillämpas för ActorId2.
  • På samma sätt framtvingas även turbaserad samtidighet för ActorId1, vilket framgår av körningen av Method1, Method2 och timerns återanrop för ActorId1 på ett seriellt sätt.
  • Körningen av Method1 för ActorId1 överlappar körningen för ActorId2. Detta beror på att turbaserad samtidighet endast framtvingas inom en aktör och inte mellan olika aktörer.
  • I vissa av metoderna/återanropskörningarna Taskslutförs (C#) / CompletableFuture(Java) som returneras av metoden/återanropet när metoden returneras. I vissa andra har den asynkrona åtgärden redan slutförts när metoden/återanropet returneras. I båda fallen frigörs låset per aktör först när både metoden/återanropet returneras och den asynkrona åtgärden har slutförts.

Återinträde

Actors-körningen tillåter återaktivering som standard. Det innebär att om en aktörsmetod i Aktör A anropar en metod på aktör B, som i sin tur anropar en annan metod på aktör A, tillåts den metoden att köras. Det beror på att den ingår i samma logiska anropskedja. Alla timer- och påminnelseanrop börjar med den nya logiska anropskontexten. Mer information finns i Reliable Actors-återaktivering .

Omfång för samtidighetsgarantier

Actors-körningen ger dessa samtidighetsgarantier i situationer där den styr anropet av dessa metoder. Den ger till exempel dessa garantier för de metodanrop som görs som svar på en klientbegäran, samt för timer- och påminnelseanrop. Men om aktörskoden direkt anropar dessa metoder utanför de mekanismer som tillhandahålls av Actors-körningen kan körningen inte ge några samtidighetsgarantier. Om metoden till exempel anropas i kontexten för en aktivitet som inte är associerad med uppgiften som returneras av aktörsmetoderna kan körningen inte ge samtidighetsgarantier. Om metoden anropas från en tråd som aktören skapar på egen hand kan körningen inte heller ge samtidighetsgarantier. För att utföra bakgrundsåtgärder bör aktörerna därför använda aktörstimers och aktörspåminnelser som respekterar turbaserad samtidighet.

Nästa steg

Kom igång genom att skapa din första Reliable Actors-tjänst: