Modalità d'uso della piattaforma Service Fabric da parte di Reliable ActorsHow Reliable Actors use the Service Fabric platform

Questo articolo descrive il funzionamento di Reliable Actors sulla piattaforma Service Fabric di Azure.This article explains how Reliable Actors work on the Azure Service Fabric platform. Reliable Actors viene eseguito in un framework ospitato in un'implementazione di un servizio Reliable Services con stato denominato servizio attore.Reliable Actors run in a framework that is hosted in an implementation of a stateful reliable service called the actor service. Il servizio attore contiene tutti i componenti necessari per gestire il ciclo di vita e l'invio di messaggi per gli attori:The actor service contains all the components necessary to manage the lifecycle and message dispatching for your actors:

  • Il runtime di Actors gestisce il ciclo di vita e la Garbage Collection e applica l'accesso a thread singolo.The Actor Runtime manages lifecycle, garbage collection, and enforces single-threaded access.
  • Un listener di comunicazione remota del servizio Actor accetta chiamate di accesso remoto per gli attori e le invia a un dispatcher per l'indirizzamento all'istanza d attore appropriata.An actor service remoting listener accepts remote access calls to actors and sends them to a dispatcher to route to the appropriate actor instance.
  • Il provider di stato degli attori esegue il wrapping dei provider di stato (come il provider di stato Reliable Collections) e fornisce un adattatore per la gestione dello stato degli attori.The Actor State Provider wraps state providers (such as the Reliable Collections state provider) and provides an adapter for actor state management.

Questi componenti insieme costituiscono il framework Reliable Actors.These components together form the Reliable Actor framework.

Livelli del servizioService layering

Dato che il servizio attore stesso è un servizio Reliable Services, tutti i concetti di modello applicativo, ciclo di vita, creazione pacchetti, distribuzione, aggiornamento e ridimensionamento validi per Reliable Services si applicano anche ai servizi attore.Because the actor service itself is a reliable service, all the application model, lifecycle, packaging, deployment, upgrade, and scaling concepts of Reliable Services apply the same way to actor services.

Livelli del servizio attore

Il diagramma precedente mostra la relazione tra i framework applicativi di Service Fabric e il codice utente.The preceding diagram shows the relationship between the Service Fabric application frameworks and user code. Gli elementi blu rappresentano il framework applicativo di Reliable Services, quelli arancioni il framework Reliable Actors e quelli verdi il codice utente.Blue elements represent the Reliable Services application framework, orange represents the Reliable Actor framework, and green represents user code.

In Reliable Services il servizio eredita la classe StatefulService.In Reliable Services, your service inherits the StatefulService class. Questa classe è a sua volta derivata da StatefulServiceBase (o StatelessService per i servizi senza stato).This class is itself derived from StatefulServiceBase (or StatelessService for stateless services). In Reliable Actors usare il servizio attore.In Reliable Actors, you use the actor service. Il servizio attore è un'implementazione diversa della classe StatefulServiceBase che implementa lo schema dell'attore in cui vengono eseguiti gli attori.The actor service is a different implementation of the StatefulServiceBase class that implements the actor pattern where your actors run. Dato che il servizio attore è semplicemente un'implementazione di StatefulServiceBase, si può scrivere il proprio servizio che deriva da ActorService e implementare le funzionalità a livello di servizio così come si farebbe quando si eredita StatefulService, ad esempio:Because the actor service itself is just an implementation of StatefulServiceBase, you can write your own service that derives from ActorService and implement service-level features the same way you would when inheriting StatefulService, such as:

  • Backup e ripristino del servizio.Service backup and restore.
  • Funzionalità condivisa per tutti gli attori, ad esempio un interruttore.Shared functionality for all actors, for example, a circuit breaker.
  • Chiamate di routine remote sul servizio attore stesso e su ogni singolo attore.Remote procedure calls on the actor service itself and on each individual actor.

Nota

I servizi con stato non sono attualmente supportati in Java/Linux.Stateful services are not currently supported in Java/Linux.

Uso del servizio attoreUsing the actor service

Le istanze degli attori hanno accesso al servizio attore in cui sono in esecuzione.Actor instances have access to the actor service in which they are running. Tramite il servizio attore, le istanze degli attori possono ottenere il contesto del servizio a livello di codice.Through the actor service, actor instances can programmatically obtain the service context. Il contesto del servizio include l'ID partizione, il nome del servizio, il nome dell'applicazione e altre informazioni specifiche sulla piattaforma Service Fabric:The service context has the partition ID, service name, application name, and other Service Fabric platform-specific information:

Task MyActorMethod()
{
    Guid partitionId = this.ActorService.Context.PartitionId;
    string serviceTypeName = this.ActorService.Context.ServiceTypeName;
    Uri serviceInstanceName = this.ActorService.Context.ServiceName;
    string applicationInstanceName = this.ActorService.Context.CodePackageActivationContext.ApplicationName;
}
CompletableFuture<?> MyActorMethod()
{
    UUID partitionId = this.getActorService().getServiceContext().getPartitionId();
    String serviceTypeName = this.getActorService().getServiceContext().getServiceTypeName();
    URI serviceInstanceName = this.getActorService().getServiceContext().getServiceName();
    String applicationInstanceName = this.getActorService().getServiceContext().getCodePackageActivationContext().getApplicationName();
}

Come tutti i servizi Reliable Services, il servizio attore deve essere registrato con un tipo di servizio nel runtime di Service Fabric.Like all Reliable Services, the actor service must be registered with a service type in the Service Fabric runtime. Perché il servizio attore possa eseguire le istanze degli attori, è necessario che anche il proprio tipo di attore sia registrato con il servizio attore.For the actor service to run your actor instances, your actor type must also be registered with the actor service. Il metodo di registrazione ActorRuntime esegue questa attività per gli attori.The ActorRuntime registration method performs this work for actors. Nel caso più semplice, è sufficiente registrare il tipo di attore e verrà usato implicitamente il servizio attore con le impostazioni predefinite:In the simplest case, you can just register your actor type, and the actor service with default settings will implicitly be used:

static class Program
{
    private static void Main()
    {
        ActorRuntime.RegisterActorAsync<MyActor>().GetAwaiter().GetResult();

        Thread.Sleep(Timeout.Infinite);
    }
}

In alternativa, è possibile usare un'espressione lambda fornita dal metodo di registrazione per creare manualmente il servizio attore.Alternatively, you can use a lambda provided by the registration method to construct the actor service yourself. È possibile perciò configurare il servizio attore e costruire esplicitamente le istanze degli attori, in cui possono essere inserite le dipendenze per l'attore mediante il relativo costruttore:You can then configure the actor service and explicitly construct your actor instances, where you can inject dependencies to your actor through its constructor:

static class Program
{
    private static void Main()
    {
        ActorRuntime.RegisterActorAsync<MyActor>(
            (context, actorType) => new ActorService(context, actorType, () => new MyActor()))
            .GetAwaiter().GetResult();

        Thread.Sleep(Timeout.Infinite);
    }
}
static class Program
{
    private static void Main()
    {
      ActorRuntime.registerActorAsync(
              MyActor.class,
              (context, actorTypeInfo) -> new FabricActorService(context, actorTypeInfo),
              timeout);

        Thread.sleep(Long.MAX_VALUE);
    }
}

Metodi del servizio attoreActor service methods

Il servizio attore implementa IActorService (C#) o ActorService (Java), che a sua volta implementa IService (C#) o Service (Java).The Actor service implements IActorService (C#) or ActorService (Java), which in turn implements IService (C#) or Service (Java). Questo è l'interfaccia usata dalla comunicazione remota di Reliable Services, che consente le chiamate RPC sui metodi del servizio.This is the interface used by Reliable Services remoting, which allows remote procedure calls on service methods. Contiene i metodi a livello di servizio che possono essere chiamati in remoto mediante la comunicazione remota del servizio.It contains service-level methods that can be called remotely via service remoting.

Enumerazione degli attoriEnumerating actors

Il servizio attore consente al client di enumerare i metadati relativi agli attori ospitati dal servizio.The actor service allows a client to enumerate metadata about the actors that the service is hosting. Dato che il servizio attore è un servizio con stato partizionato, l'enumerazione viene eseguita per partizione.Because the actor service is a partitioned stateful service, enumeration is performed per partition. Poiché ogni partizione può contenere molti attori, l'enumerazione viene restituita come set di risultati a pagine.Because each partition might contain many actors, the enumeration is returned as a set of paged results. Le pagine vengono esaminate in ciclo fino a quando non vengono lette tutte.The pages are looped over until all pages are read. L'esempio seguente illustra come creare un elenco di tutti gli attori attivi in una partizione di un servizio Actor:The following example shows how to create a list of all active actors in one partition of an actor service:

IActorService actorServiceProxy = ActorServiceProxy.Create(
    new Uri("fabric:/MyApp/MyService"), partitionKey);

ContinuationToken continuationToken = null;
List<ActorInformation> activeActors = new List<ActorInformation>();

do
{
    PagedResult<ActorInformation> page = await actorServiceProxy.GetActorsAsync(continuationToken, cancellationToken);

    activeActors.AddRange(page.Items.Where(x => x.IsActive));

    continuationToken = page.ContinuationToken;
}
while (continuationToken != null);
ActorService actorServiceProxy = ActorServiceProxy.create(
    new URI("fabric:/MyApp/MyService"), partitionKey);

ContinuationToken continuationToken = null;
List<ActorInformation> activeActors = new ArrayList<ActorInformation>();

do
{
    PagedResult<ActorInformation> page = actorServiceProxy.getActorsAsync(continuationToken);

    while(ActorInformation x: page.getItems())
    {
         if(x.isActive()){
              activeActors.add(x);
         }
    }

    continuationToken = page.getContinuationToken();
}
while (continuationToken != null);

Eliminazione di attoriDeleting actors

Il servizio attore fornisce anche una funzione per l'eliminazione degli attori:The actor service also provides a function for deleting actors:

ActorId actorToDelete = new ActorId(id);

IActorService myActorServiceProxy = ActorServiceProxy.Create(
    new Uri("fabric:/MyApp/MyService"), actorToDelete);

await myActorServiceProxy.DeleteActorAsync(actorToDelete, cancellationToken)
ActorId actorToDelete = new ActorId(id);

ActorService myActorServiceProxy = ActorServiceProxy.create(
    new URI("fabric:/MyApp/MyService"), actorToDelete);

myActorServiceProxy.deleteActorAsync(actorToDelete);

Per altre informazioni sull'eliminazione degli attori e il relativo stato, vedere la documentazione sul ciclo di vita degli attori.For more information on deleting actors and their state, see the actor lifecycle documentation.

Servizio attore personalizzatoCustom actor service

Usando l'espressione lambda di registrazione dell'attore è possibile registrare il proprio servizio attore personalizzato che deriva da ActorService (C#) e FabricActorService (Java).By using the actor registration lambda, you can register your own custom actor service that derives from ActorService (C#) and FabricActorService (Java). In questo servizio attore personalizzato è possibile implementare funzionalità di livello di servizio scrivendo una classe di servizio che eredita ActorService (C#) o FabricActorService (Java).In this custom actor service, you can implement your own service-level functionality by writing a service class that inherits ActorService (C#) or FabricActorService (Java). Un servizio attore personalizzato eredita tutte le funzionalità di runtime dell'attore da ActorService (C#) o FabricActorService (Java) e può essere usato per implementare i propri metodi del servizio.A custom actor service inherits all the actor runtime functionality from ActorService (C#) or FabricActorService (Java) and can be used to implement your own service methods.

class MyActorService : ActorService
{
    public MyActorService(StatefulServiceContext context, ActorTypeInformation typeInfo, Func<ActorBase> newActor)
        : base(context, typeInfo, newActor)
    { }
}
class MyActorService extends FabricActorService
{
    public MyActorService(StatefulServiceContext context, ActorTypeInformation typeInfo, BiFunction<FabricActorService, ActorId, ActorBase> newActor)
    {
         super(context, typeInfo, newActor);
    }
}
static class Program
{
    private static void Main()
    {
        ActorRuntime.RegisterActorAsync<MyActor>(
            (context, actorType) => new MyActorService(context, actorType, () => new MyActor()))
            .GetAwaiter().GetResult();

        Thread.Sleep(Timeout.Infinite);
    }
}
public class Program
{
    public static void main(String[] args)
    {
        ActorRuntime.registerActorAsync(
                MyActor.class,
                (context, actorTypeInfo) -> new FabricActorService(context, actorTypeInfo),
                timeout);
        Thread.sleep(Long.MAX_VALUE);
    }
}

Implementazione del backup e ripristino dell'attoreImplementing actor backup and restore

Nell'esempio seguente il servizio attore personalizzato espone un metodo per il backup dei dati dell'attore sfruttando il listener di comunicazione remota già presente in ActorService:In the following example, the custom actor service exposes a method to back up actor data by taking advantage of the remoting listener already present in ActorService:

public interface IMyActorService : IService
{
    Task BackupActorsAsync();
}

class MyActorService : ActorService, IMyActorService
{
    public MyActorService(StatefulServiceContext context, ActorTypeInformation typeInfo, Func<ActorBase> newActor)
        : base(context, typeInfo, newActor)
    { }

    public Task BackupActorsAsync()
    {
        return this.BackupAsync(new BackupDescription(PerformBackupAsync));
    }

    private async Task<bool> PerformBackupAsync(BackupInfo backupInfo, CancellationToken cancellationToken)
    {
        try
        {
           // store the contents of backupInfo.Directory
           return true;
        }
        finally
        {
           Directory.Delete(backupInfo.Directory, recursive: true);
        }
    }
}
public interface MyActorService extends Service
{
    CompletableFuture<?> backupActorsAsync();
}

class MyActorServiceImpl extends ActorService implements MyActorService
{
    public MyActorService(StatefulServiceContext context, ActorTypeInformation typeInfo, Func<FabricActorService, ActorId, ActorBase> newActor)
    {
       super(context, typeInfo, newActor);
    }

    public CompletableFuture backupActorsAsync()
    {
        return this.backupAsync(new BackupDescription((backupInfo, cancellationToken) -> performBackupAsync(backupInfo, cancellationToken)));
    }

    private CompletableFuture<Boolean> performBackupAsync(BackupInfo backupInfo, CancellationToken cancellationToken)
    {
        try
        {
           // store the contents of backupInfo.Directory
           return true;
        }
        finally
        {
           deleteDirectory(backupInfo.Directory)
        }
    }

    void deleteDirectory(File file) {
        File[] contents = file.listFiles();
        if (contents != null) {
            for (File f : contents) {
               deleteDirectory(f);
             }
        }
        file.delete();
    }
}

In questo esempio IMyActorService è un contratto di comunicazione remota che implementa IService (C#) and Service (Java) e viene successivamente implementato da MyActorService.In this example, IMyActorService is a remoting contract that implements IService (C#) and Service (Java), and is then implemented by MyActorService. Aggiungendo questo contratto di comunicazione remota, i metodi su IMyActorService ora sono disponibili anche per un client attraverso la creazione di un proxy di comunicazione remota mediante ActorServiceProxy:By adding this remoting contract, methods on IMyActorService are now also available to a client by creating a remoting proxy via ActorServiceProxy:

IMyActorService myActorServiceProxy = ActorServiceProxy.Create<IMyActorService>(
    new Uri("fabric:/MyApp/MyService"), ActorId.CreateRandom());

await myActorServiceProxy.BackupActorsAsync();
MyActorService myActorServiceProxy = ActorServiceProxy.create(MyActorService.class,
    new URI("fabric:/MyApp/MyService"), actorId);

myActorServiceProxy.backupActorsAsync();

Modello di applicazioneApplication model

I servizi Actor sono servizi Reliable Services, per cui il modello applicativo è lo stesso.Actor services are Reliable Services, so the application model is the same. Tuttavia, gli strumenti di compilazione del framework attore generano automaticamente alcuni dei file del modello applicativo.However, the actor framework build tools generate some of the application model files for you.

Manifesto del servizioService manifest

Gli strumenti di compilazione del framework attore generano automaticamente il contenuto del file ServiceManifest.xml del servizio attore.The actor framework build tools automatically generate the contents of your actor service's ServiceManifest.xml file. Questo file include:This file includes:

  • Tipo del servizio attore.Actor service type. Il nome del tipo viene generato in base al nome del progetto attore.The type name is generated based on your actor's project name. In base all'attributo di persistenza nell'attore, viene impostato anche il flag HasPersistedState.Based on the persistence attribute on your actor, the HasPersistedState flag is also set accordingly.
  • Pacchetto di codice.Code package.
  • Pacchetto di configurazione.Config package.
  • Risorse ed endpoint.Resources and endpoints.

Manifesto dell'applicazioneApplication manifest

Gli strumenti di compilazione del framework attore creano automaticamente una definizione del servizio predefinito per il servizio Actor.The actor framework build tools automatically create a default service definition for your actor service. Gli strumenti di compilazione popolano le proprietà del servizio predefinito:The build tools populate the default service properties:

  • Il numero di set di repliche è determinato dall'attributo di persistenza sull'attore.Replica set count is determined by the persistence attribute on your actor. Ogni volta che viene modificato l'attributo di persistenza nell'attore, viene reimpostato di conseguenza il numero di set di repliche nella definizione del servizio predefinito.Each time the persistence attribute on your actor is changed, the replica set count in the default service definition is reset accordingly.
  • Lo schema e l'intervallo della partizione vengono impostati su Uniform Int64 con l'intervallo di chiavi Int64 completo.Partition scheme and range are set to Uniform Int64 with the full Int64 key range.

Concetti relativi alla partizione di Service Fabric per gli attoriService Fabric partition concepts for actors

I servizi Actor sono servizi con stato partizionati.Actor services are partitioned stateful services. Ogni partizione di un servizio Actor contiene un set di attori.Each partition of an actor service contains a set of actors. Le partizioni del servizio vengono distribuite automaticamente su più nodi in Service Fabric.Service partitions are automatically distributed over multiple nodes in Service Fabric. Le istanze degli attori vengono distribuite di conseguenza.Actor instances are distributed as a result.

Partizionamento e distribuzione degli attori

È possibile creare servizi Reliable Services con schemi di partizione e intervalli di chiavi di partizione diversi.Reliable Services can be created with different partition schemes and partition key ranges. Il servizio attore usa lo schema di partizionamento Int64 con l'intervallo di chiavi Int64 completo per mappare gli attori alle partizioni.The actor service uses the Int64 partitioning scheme with the full Int64 key range to map actors to partitions.

ID attoreActor ID

A ogni attore creato nel servizio è associato un ID univoco, rappresentato dalla classe ActorId .Each actor that's created in the service has a unique ID associated with it, represented by the ActorId class. ActorId è un valore ID opaco che può essere usato per la distribuzione uniforme degli attori nelle partizioni del servizio mediante la generazione di ID casuali:ActorId is an opaque ID value that can be used for uniform distribution of actors across the service partitions by generating random IDs:

ActorProxy.Create<IMyActor>(ActorId.CreateRandom());
ActorProxyBase.create<MyActor>(MyActor.class, ActorId.newId());

Di ogni ActorId viene eseguito l'hashing in un Int64.Every ActorId is hashed to an Int64. Per questo motivo il servizio attore deve usare uno schema di partizionamento Int64 con l'intervallo di chiavi Int64 completo.This is why the actor service must use an Int64 partitioning scheme with the full Int64 key range. È comunque possibile usare valori ID personalizzati per un ActorID, tra cui GUID/UUID, stringhe e Int64.However, custom ID values can be used for an ActorID, including GUIDs/UUIDs, strings, and Int64s.

ActorProxy.Create<IMyActor>(new ActorId(Guid.NewGuid()));
ActorProxy.Create<IMyActor>(new ActorId("myActorId"));
ActorProxy.Create<IMyActor>(new ActorId(1234));
ActorProxyBase.create(MyActor.class, new ActorId(UUID.randomUUID()));
ActorProxyBase.create(MyActor.class, new ActorId("myActorId"));
ActorProxyBase.create(MyActor.class, new ActorId(1234));

Quando si usano GUID/UUID e stringhe, viene eseguito l'hashing dei valori in un Int64.When you're using GUIDs/UUIDs and strings, the values are hashed to an Int64. Quando invece si fornisce esplicitamente un Int64 a un ActorId, l'Int64 verrà mappato direttamente a una partizione senza ulteriore hashing.However, when you're explicitly providing an Int64 to an ActorId, the Int64 will map directly to a partition without further hashing. È possibile usare questa tecnica per controllare in quale partizione vengono inseriti gli attori.You can use this technique to control which partition the actors are placed in.

Attore che usa lo stack di comunicazione remota V2Actor using Remoting V2 Stack

Con il pacchetto NuGet 2.8, gli utenti possono usare lo stack V2 per la comunicazione remota, che è più efficiente e fornisce funzioni quali la serializzazione personalizzata.With 2.8 nuget package, users can now use Remoting V2 stack, which is more performant and provides features like custom Serialization. La comunicazione remota V2 non è compatibile con le versioni precedenti dello stack di comunicazione remota esistente, che è stato definito stack V1 di comunicazione remota.Remoting V2 is not backward compatible with existing Remoting stack (we are calling now it as V1 Remoting stack).

Le modifiche seguenti sono necessarie per usare lo stack V2 di comunicazione remota.Following changes are required to use the Remoting V2 Stack.

  1. Aggiungere l'attributo assembly seguente nell'interfaccia dell'attore.Add the following assembly attribute on Actor Interfaces.

    [assembly:FabricTransportActorRemotingProvider(RemotingListener = RemotingListener.V2Listener,RemotingClient = RemotingClient.V2Client)]
    
  2. Compilare e aggiornare ActorService e i progetti client dell'attore per iniziare a usare lo stack V2.Build and Upgrade ActorService And Actor Client projects to start using V2 Stack.

Aggiornamento del servizio Actor allo stack V2 di comunicazione remota senza compromettere la disponibilità del servizio.Actor Service Upgrade to Remoting V2 Stack without impacting Service Availability.

Questa modifica sarà un aggiornamento in due passaggi.This change will be a 2-step upgrade. Seguire i passaggi nella sequenza elencata.Follow the steps in the same sequence as listed.

  1. Aggiungere l'attributo assembly seguente nell'interfaccia dell'attore.Add the following assembly attribute on Actor Interfaces. Questo attributo avvierà due listener per ActorService, il listener V1 esistente e il listener V2.This attribute will start two listeners for ActorService, V1 (existing) and V2 Listener. Eseguire l'aggiornamento di ActorService con questa modifica.Upgrade ActorService with this change.

    [assembly:FabricTransportActorRemotingProvider(RemotingListener = RemotingListener.CompatListener,RemotingClient = RemotingClient.V2Client)]
    
  2. Eseguire l'aggiornamento di ActorClients dopo aver completato l'aggiornamento precedente.Upgrade ActorClients after completing the above upgrade. Questo passaggio garantisce che il proxy Actor usi lo stack V2 per la comunicazione remota.This step makes sure Actor Proxy is using Remoting V2 Stack.

  3. Questo passaggio è facoltativo.This step is optional. Modificare l'attributo precedente per rimuovere il listener V1.Change the above attribute to remove V1 Listener.

    [assembly:FabricTransportActorRemotingProvider(RemotingListener = RemotingListener.V2Listener,RemotingClient = RemotingClient.V2Client)]
    

Passaggi successiviNext steps