您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

Service Fabric Reliable Actors 简介Introduction to Service Fabric Reliable Actors

Reliable Actors 是基于虚拟执行组件模式的 Service Fabric 应用程序框架。Reliable Actors is a Service Fabric application framework based on the Virtual Actor pattern. Reliable Actors API 提供单一线程编程模型,该模型是基于 Service Fabric 所提供的可扩展性和可靠性保证构建的。The Reliable Actors API provides a single-threaded programming model built on the scalability and reliability guarantees provided by Service Fabric.

什么是执行组件?What are Actors?

执行组件是一个使用单线程执行的计算和状态的独立单元。An actor is an isolated, independent unit of compute and state with single-threaded execution. 执行组件模式是并发或分布式系统的计算模型。在此类系统中,大量执行组件可同时相互独立地运行。The actor pattern is a computational model for concurrent or distributed systems in which a large number of these actors can execute simultaneously and independently of each other. 执行组件可相互进行通信,并且它们可以创建更多执行组件。Actors can communicate with each other and they can create more actors.

何时使用 Reliable ActorsWhen to use Reliable Actors

Service Fabric Reliable Actors 是执行组件设计模式的实现。Service Fabric Reliable Actors is an implementation of the actor design pattern. 与任何软件设计模式一样,是否使用特定模式取决于该模式能否解决相关软件设计问题。As with any software design pattern, the decision whether to use a specific pattern is made based on whether or not a software design problem fits the pattern.

虽然执行组件设计模式可以很好的适应很多分布式系统问题和场景的需求,但是仍有必要仔细考虑该模式以及实现该模式的框架的限制。Although the actor design pattern can be a good fit to a number of distributed systems problems and scenarios, careful consideration of the constraints of the pattern and the framework implementing it must be made. 对于以下情况,通常应考虑使用执行组件模式对问题或场景进行建模:As general guidance, consider the actor pattern to model your problem or scenario if:

  • 问题空间包含大量(几千或更多)小型、独立的状态和逻辑单元。Your problem space involves a large number (thousands or more) of small, independent, and isolated units of state and logic.
  • 要处理不要求与外部组件进行大量交互的单线程对象,包括查询一组执行组件的状态。You want to work with single-threaded objects that do not require significant interaction from external components, including querying state across a set of actors.
  • 执行组件实例不会通过发出 I/O 操作,用不可预测的延迟阻止调用方。Your actor instances won't block callers with unpredictable delays by issuing I/O operations.

Service Fabric 中的执行组件Actors in Service Fabric

在 Service Fabric 中,执行组件在 Reliable Actors 框架中实现:此应用程序框架以执行组件模式为依据,在 Service Fabric Reliable Services 的基础之上构建而成。In Service Fabric, actors are implemented in the Reliable Actors framework: An actor-pattern-based application framework built on top of Service Fabric Reliable Services. 编写的每个 Reliable Actor 服务实际上都是一个已分区、有状态的 Reliable Service。Each Reliable Actor service you write is actually a partitioned, stateful Reliable Service.

每个执行组件都定义为执行组件类型的一个实例,类似于 .NET 对象是 .NET 类型的一个实例。Every actor is defined as an instance of an actor type, identical to the way a .NET object is an instance of a .NET type. 例如,可能有用于实现计算器功能的执行组件类型,并可能有很多在群集中各个节点分布的该类型的执行组件。For example, there may be an actor type that implements the functionality of a calculator and there could be many actors of that type that are distributed on various nodes across a cluster. 每个此类执行组件都由执行组件 ID 唯一标识。Each such actor is uniquely identified by an actor ID.

执行组件生存期Actor Lifetime

Service Fabric 执行组件是虚拟的,这表示其生存期不依赖于其内存中表示形式。Service Fabric actors are virtual, meaning that their lifetime is not tied to their in-memory representation. 因此,它们不需要显式创建或销毁。As a result, they do not need to be explicitly created or destroyed. Reliable Actors 运行时会在它第一次接收到执行组件 ID 的请求时自动激活此执行组件。The Reliable Actors runtime automatically activates an actor the first time it receives a request for that actor ID. 如果一段时间未使用某个执行组件,则 Reliable Actors 运行时会回收此内存对象。If an actor is not used for a period of time, the Reliable Actors runtime garbage-collects the in-memory object. 它还将掌握此执行组件的存在信息,以便将来重新激活。It will also maintain knowledge of the actor's existence should it need to be reactivated later. 如需了解更多详情,请参阅执行组件生命周期和垃圾回收For more details, see Actor lifecycle and garbage collection.

虚拟执行组件生命周期抽象因虚拟执行组件模型而产生一些注意事项,实际上 Reliable Actors 实现有时会偏离此模型。This virtual actor lifetime abstraction carries some caveats as a result of the virtual actor model, and in fact the Reliable Actors implementation deviates at times from this model.

  • 当第一次将消息发送到执行组件的执行组件 ID 时将自动激活此执行组件,并由此构造执行组件对象。An actor is automatically activated (causing an actor object to be constructed) the first time a message is sent to its actor ID. 在一段时间之后,将回收此执行组件对象。After some period of time, the actor object is garbage collected. 将来可以再次使用此执行组件 ID 来构造新的执行组件对象。In the future, using the actor ID again, causes a new actor object to be constructed. 在状态管理器中存储时,执行组件的状态的生命周期比此对象的生命周期长。An actor's state outlives the object's lifetime when stored in the state manager.
  • 针对某个执行组件 ID 调用任何执行组件方法可激活此执行组件。Calling any actor method for an actor ID activates that actor. 出于此原因,执行组件类型允许运行时隐式调用其构造函数。For this reason, actor types have their constructor called implicitly by the runtime. 因此,虽然可通过服务将参数传递给执行组件的构造函数,但是客户端代码无法将参数传递给执行组件类型的构造函数。Therefore, client code cannot pass parameters to the actor type's constructor, although parameters may be passed to the actor's constructor by the service itself. 结果是如果执行组件需要客户端的初始化参数,则在对其调用其他方法时在部分初始化状态下构造执行组件。The result is that actors may be constructed in a partially-initialized state by the time other methods are called on it, if the actor requires initialization parameters from the client. 从客户端激活执行组件不存在单一的入口点。There is no single entry point for the activation of an actor from the client.
  • 虽然 Reliable Actors 隐式创建执行组件对象,但仍可显示删除执行组件及其状态。Although Reliable Actors implicitly create actor objects; you do have the ability to explicitly delete an actor and its state.

分布和故障转移Distribution and failover

要提供伸缩性和可靠性,Service Fabric 在整个群集中分布执行组件,并根据需要自动将其从故障节点迁移到正常节点中。To provide scalability and reliability, Service Fabric distributes actors throughout the cluster and automatically migrates them from failed nodes to healthy ones as required. 这是对已分区的有状态 Reliable Service 进行抽象。This is an abstraction over a partitioned, stateful Reliable Service. 由于执行组件在名为执行组件服务的有状态 Reliable Service 内部运行,因此分布、可伸缩性、可靠性和自动故障转移全都可提供。Distribution, scalability, reliability, and automatic failover are all provided by virtue of the fact that actors are running inside a stateful Reliable Service called the Actor Service.

执行组件在执行组件服务的各个分区中分布,而这些分区在一个 Service Fabric 群集的各个节点中分布。Actors are distributed across the partitions of the Actor Service, and those partitions are distributed across the nodes in a Service Fabric cluster. 每个服务分区包含一组执行组件。Each service partition contains a set of actors. Service Fabric 管理服务分区的分布和故障转移。Service Fabric manages distribution and failover of the service partitions.

例如,将按以下方式分布具有九个分区的执行组件服务,这些分区使用默认的执行组件分区放置方案部署到三个节点:For example, an actor service with nine partitions deployed to three nodes using the default actor partition placement would be distributed thusly:

Reliable Actors 分布

执行组件框架用于管理分区方案和键范围设置。The Actor Framework manages partition scheme and key range settings for you. 这可以简化一些选择,但同时也要注意以下情况:This simplifies some choices but also carries some consideration:

  • Reliable Services 允许选择分区方案、键范围(当使用范围分区方案时)和分区计数。Reliable Services allows you to choose a partitioning scheme, key range (when using a range partitioning scheme), and partition count. Reliable Actors 仅限于使用范围分区方案(统一 Int64 方案),要求用户使用完整的 Int64 键范围。Reliable Actors is restricted to the range partitioning scheme (the uniform Int64 scheme) and requires you use the full Int64 key range.
  • 默认情况下,执行组件被随机放到分区中,因此而形成统一分布。By default, actors are randomly placed into partitions resulting in uniform distribution.
  • 因为执行组件是随机分布的,所以预计执行组件的操作将始终需要网络通信,包括对方法调用数据的序列化和反序列化,这会产生延迟和开销。Because actors are randomly placed, it should be expected that actor operations will always require network communication, including serialization and deserialization of method call data, incurring latency and overhead.
  • 在高级方案中,可使用映射到特定分区的 Int64 执行组件 ID 控制执行组件分区放置。In advanced scenarios, it is possible to control actor partition placement by using Int64 actor IDs that map to specific partitions. 但是,这样做会导致分区间的执行组件的分布不平衡。However, doing so can result in an unbalanced distribution of actors across partitions.

若要详细了解如何对执行组件服务进行分区,请参阅执行组件的分区概念For more information on how actor services are partitioned, refer to partitioning concepts for actors.

执行组件通信Actor communication

执行组件交互在接口中定义,该接口由实现接口的执行组件和通过相同接口获取执行组件代理的客户端共享。Actor interactions are defined in an interface that is shared by the actor that implements the interface, and the client that gets a proxy to an actor via the same interface. 因为该接口用于异步调用执行组件方法,所以接口的每个方法都必须是返回任务的方法。Because this interface is used to invoke actor methods asynchronously, every method on the interface must be Task-returning.

由于方法的调用及其响应最终导致跨群集的网络请求,因此必须通过平台对这些请求的参数以及所返回的任务的结果类型进行序列化。Method invocations and their responses ultimately result in network requests across the cluster, so the arguments and the result types of the tasks that they return must be serializable by the platform. 特别是,它们必须可进行数据协定序列化In particular, they must be data contract serializable.

执行组件代理The actor proxy

Reliable Actors 客户端 API 提供一个执行组件实例和一个执行组件客户端之间的通信。The Reliable Actors client API provides communication between an actor instance and an actor client. 若要与执行组件进行通信,客户端需创建实现执行组件接口的执行组件代理对象。To communicate with an actor, a client creates an actor proxy object that implements the actor interface. 客户端通过调用代理对象上的方法与执行组件进行交互。The client interacts with the actor by invoking methods on the proxy object. 执行组件代理可以用于从客户端到执行组件以及从执行组件到执行组件的通信。The actor proxy can be used for client-to-actor and actor-to-actor communication.

// 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();

请注意用于创建执行组件代理对象的两条信息为执行组件 ID 和应用程序名称。Note that the two pieces of information used to create the actor proxy object are the actor ID and the application name. 执行组件 ID 用于唯一标识执行组件,而应用程序名称用于标识其中部署执行组件的 Service Fabric 应用程序The actor ID uniquely identifies the actor, while the application name identifies the Service Fabric application where the actor is deployed.

客户端上的 ActorProxy(C#) / ActorProxyBase(Java) 类执行必要的解析工作,以便按 ID 查找执行组件,并使用该执行组件打开信道。The ActorProxy(C#) / ActorProxyBase(Java) class on the client side performs the necessary resolution to locate the actor by ID and open a communication channel with it. 如果出现通信故障和故障转移,它还会重新尝试查找执行组件。It also retries to locate the actor in the cases of communication failures and failovers. 因此,消息传送具有以下特征:As a result, message delivery has the following characteristics:

  • 消息传送将尽力而为。Message delivery is best effort.
  • 执行组件可能会收到来自同一客户端的重复消息。Actors may receive duplicate messages from the same client.

并发Concurrency

Reliable Actors 运行时提供简单的基于轮次的访问模型用于访问执行组件方法。The Reliable Actors runtime provides a simple turn-based access model for accessing actor methods. 这意味着任何时候执行组件对象的代码内仅有一个活动线程。This means that no more than one thread can be active inside an actor object's code at any time. 基于轮次的访问极大简化了并发系统,因为无需使用数据访问的同步机制。Turn-based access greatly simplifies concurrent systems as there is no need for synchronization mechanisms for data access. 它还意味着系统的设计必须特别考虑每个执行组件实例的单线程访问性质。It also means systems must be designed with special considerations for the single-threaded access nature of each actor instance.

  • 单个执行组件实例一次只能处理一个请求。A single actor instance cannot process more than one request at a time. 如果需要处理并发请求,那么一个执行组件实例会导致出现吞吐量瓶颈。An actor instance can cause a throughput bottleneck if it is expected to handle concurrent requests.
  • 如果两个执行组件之间存在一个循环请求,并且同时向其中一个执行组件发送外部请求,那么这两个执行组件就会发生互相死锁的情况。Actors can deadlock on each other if there is a circular request between two actors while an external request is made to one of the actors simultaneously. 执行组件运行时在执行组件调用上会自动超时,并向调用方抛出异常,以便中断可能出现的死锁情况。The actor runtime will automatically time out on actor calls and throw an exception to the caller to interrupt possible deadlock situations.

Reliable Actors 通信

基于轮次的访问Turn-based access

一个轮次包含完全执行用于响应其他执行组件或客户端的请求的执行组件方法,或完全执行计时器/提醒回叫。A turn consists of the complete execution of an actor method in response to a request from other actors or clients, or the complete execution of a timer/reminder callback. 即使这些方法和回调是异步的,执行组件运行时也不会交替执行它们。Even though these methods and callbacks are asynchronous, the Actors runtime does not interleave them. 必须彻底完成一个轮次,才允许启动新的轮次。A turn must be fully finished before a new turn is allowed. 换而言之,在允许新的方法调用或回调之前必须彻底完成当前正在执行的执行组件方法或计时器/提醒回调。In other words, an actor method or timer/reminder callback that is currently executing must be fully finished before a new call to a method or callback is allowed. 如果执行已从方法或回调中返回,且由方法或回调返回的任务已完成,则将此方法或回调视为已完成。A method or callback is considered to have finished if the execution has returned from the method or callback and the task returned by the method or callback has finished. 值得强调的是,即使在不同的方法、计时器和回调中,也遵从基于轮次的并发执行。It is worth emphasizing that turn-based concurrency is respected even across different methods, timers, and callbacks.

通过在轮次的开始获取按执行组件锁并在轮次的结束释放锁,执行组件运行时强制执行基于轮次的并发。The Actors runtime enforces turn-based concurrency by acquiring a per-actor lock at the beginning of a turn and releasing the lock at the end of the turn. 因此,基于按执行组件基础而非所有执行组件强制执行基于轮次的并发。Thus, turn-based concurrency is enforced on a per-actor basis and not across actors. 执行组件方法和计时器/提醒回调可以代表不同执行组件同时执行。Actor methods and timer/reminder callbacks can execute simultaneously on behalf of different actors.

以下示例对上述概念进行了说明。The following example illustrates the above concepts. 假设一种类型的执行组件实现两个异步方法(即 Method1Method2)、一个计时器和一个提醒。Consider an actor type that implements two asynchronous methods (say, Method1 and Method2), a timer, and a reminder. 下面的示例图展示了代表属于这种执行组件类型的两个执行组件(ActorId1ActorId2)执行这些方法和回叫的时间线。The diagram below shows an example of a timeline for the execution of these methods and callbacks on behalf of two actors (ActorId1 and ActorId2) that belong to this actor type.

Reliable Actors 运行时基于轮次的并发执行和访问

该图遵循以下约定:This diagram follows these conventions:

  • 每条垂直线显示代表特定执行组件执行方法或回调的逻辑流。Each vertical line shows the logical flow of execution of a method or a callback on behalf of a particular actor.
  • 每条垂直线上标记的事件按时间顺序发生,较新事件发生在较旧事件之后。The events marked on each vertical line occur in chronological order, with newer events occurring below older ones.
  • 时间线上使用不同的颜色对应不同的执行组件。Different colors are used for timelines corresponding to different actors.
  • 突出显示用于指示代表方法或回调保持按执行组件锁的持续时间。Highlighting is used to indicate the duration for which the per-actor lock is held on behalf of a method or callback.

要重点考虑的几点:Some important points to consider:

  • 当代表 ActorId2 执行 Method1 以响应客户端请求 xyz789 时,收到另一个客户端请求 (abc123),也要求由 ActorId2 执行 Method1While Method1 is executing on behalf of ActorId2 in response to client request xyz789, another client request (abc123) arrives that also requires Method1 to be executed by ActorId2. 不过,在上一次执行完成之前,不会开始第二次执行 Method1However, the second execution of Method1 does not begin until the prior execution has finished. 同样,在执行 Method1 以响应客户端请求 xyz789 时,触发了 ActorId2 注册的提醒。Similarly, a reminder registered by ActorId2 fires while Method1 is being executed in response to client request xyz789. 只有当这两次 Method1 执行都完成之后,才会执行提醒回叫。The reminder callback is executed only after both executions of Method1 are complete. 一切都是因为,为 ActorId2 强制执行基于轮次的并发。All of this is due to turn-based concurrency being enforced for ActorId2.
  • 同样,也为 ActorId1 强制执行了基于轮次的并发,代表 ActorId1 以串行方式执行 Method1Method2 和计时器回叫就表明了这一点。Similarly, turn-based concurrency is also enforced for ActorId1, as demonstrated by the execution of Method1, Method2, and the timer callback on behalf of ActorId1 happening in a serial fashion.
  • 代表 ActorId1 执行 Method1 与代表 ActorId2 执行此方法相互重叠。Execution of Method1 on behalf of ActorId1 overlaps with its execution on behalf of ActorId2. 这是因为仅在同一个执行组件内,而不是在不同执行组件之间强制执行基于轮次的并发执行。This is because turn-based concurrency is enforced only within an actor and not across actors.
  • 在一些方法/回叫执行中,方法/回叫返回的 Task(C#) / CompletableFuture(Java) 在方法返回之后完成。In some of the method/callback executions, the Task(C#) / CompletableFuture(Java) returned by the method/callback finishes after the method returns. 在另一些方法/回叫执行中,异步操作在方法/回叫返回时就已完成。In some others, the asynchronous operation has already finished by the time the method/callback returns. 在这两种情况下,只有在方法/回叫返回且异步操作已完成后,才会解除每个执行组件锁定。In both cases, the per-actor lock is released only after both the method/callback returns and the asynchronous operation finishes.

重新进入Reentrancy

执行组件运行时默认情况下允许重新进入。The Actors runtime allows reentrancy by default. 也就是说,如果 Actor A 的执行组件方法调用 Actor B 上的方法,后者反过来又调用 Actor A 上的另一个方法,则允许运行另一个方法。This means that if an actor method of Actor A calls a method on Actor B, which in turn calls another method on Actor A, that method is allowed to run. 这是因为它是同一逻辑调用链上下文的一部分。This is because it is part of the same logical call-chain context. 所有计时器和提醒调用都使用新的逻辑上下文开始。All timer and reminder calls start with the new logical call context. 如需了解更多详情,请参阅 Reliable Actors 可重入性See the Reliable Actors reentrancy for more details.

并发保证的范围Scope of concurrency guarantees

执行组件运行时在它控制调用这些方法的情况下提供这些并发保证。The Actors runtime provides these concurrency guarantees in situations where it controls the invocation of these methods. 例如,它为响应客户端请求而执行的方法调用和计时器与提醒回调提供这些保证。For example, it provides these guarantees for the method invocations that are done in response to a client request, as well as for timer and reminder callbacks. 但是,如果执行组件代码在执行组件运行时提供的机制之外直接调用这些方法,则运行时不能提供任何并发保证。However, if the actor code directly invokes these methods outside of the mechanisms provided by the Actors runtime, then the runtime cannot provide any concurrency guarantees. 例如,如果在与执行组件方法返回的任务不相关联的某项任务的上下文中调用方法,则运行时不能提供并发性保证。For example, if the method is invoked in the context of some task that is not associated with the task returned by the actor methods, then the runtime cannot provide concurrency guarantees. 如果通过执行组件依据其自身创建的线程调用方法,那么运行时也不能提供并发性保证。If the method is invoked from a thread that the actor creates on its own, then the runtime also cannot provide concurrency guarantees. 因此,若要执行后台操作,执行组件应使用遵从基于轮次的并发的执行组件计时器和执行组件提醒Therefore, to perform background operations, actors should use actor timers and actor reminders that respect turn-based concurrency.

后续步骤Next steps

从生成第一个 Reliable Actors 服务开始:Get started by building your first Reliable Actors service: