Reliable Services 入门Get started with Reliable Services

Azure Service Fabric 应用程序包含运行代码的一个或多个服务。An Azure Service Fabric application contains one or more services that run your code. 本指南说明如何使用 Reliable Services 同时创建无状态与有状态的 Service Fabric 应用程序。This guide shows you how to create both stateless and stateful Service Fabric applications with Reliable Services.

基本概念Basic concepts

了解几个基本概念,即可开始使用 Reliable Services:To get started with Reliable Services, you only need to understand a few basic concepts:

  • 服务类型:这是你的服务实现。Service type: This is your service implementation. 它由编写的可扩展 StatelessService 的类、其中使用的任何其他代码或依赖项以及名称和版本号定义。It is defined by the class you write that extends StatelessService and any other code or dependencies used therein, along with a name and a version number.
  • 命名服务实例:若要运行服务,需要创建服务类型的命名实例,就像创建类类型的对象实例一样。Named service instance: To run your service, you create named instances of your service type, much like you create object instances of a class type. 服务实例具有使用“fabric:/”方案(如“fabric:/MyApp/MyService”)的 URI 形式的名称。A service instance has a name in the form of a URI using the "fabric:/" scheme, such as "fabric:/MyApp/MyService".
  • 服务宿主:创建的命名服务实例需在主机进程中运行。Service host: The named service instances you create need to run inside a host process. 服务宿主是可以运行服务实例的进程。The service host is just a process where instances of your service can run.
  • 服务注册:通过注册可将所有对象融合在一起。Service registration: Registration brings everything together. 只有在服务宿主中将服务类型注册 Service Fabric 运行时,Service Fabric 才能创建该类型的可运行实例。The service type must be registered with the Service Fabric runtime in a service host to allow Service Fabric to create instances of it to run.

创建无状态服务Create a stateless service

无状态服务目前是云应用程序的常规服务类型。A stateless service is a type of service that is currently the norm in cloud applications. 服务之所以被视为无状态,是因为它本身不包含需要可靠存储或高度可用的数据。It is considered stateless because the service itself does not contain data that needs to be stored reliably or made highly available. 如果无状态服务的实例关闭,其所有内部状态都会丢失。If an instance of a stateless service shuts down, all of its internal state is lost. 在这种类型的服务中,必须将状态保存到外部存储(如 Azure 表或 SQL 数据库),才能实现高可用性和可靠性。In this type of service, state must be persisted to an external store, such as Azure Tables or a SQL database, for it to be made highly available and reliable.

以管理员身份启动 Visual Studio 2017 或 Visual Studio 2019,并新建一个名为 HelloWorld 的 Service Fabric 应用程序项目:Launch Visual Studio 2017 or Visual Studio 2019 as an administrator, and create a new Service Fabric application project named HelloWorld:

使用“新建项目”对话框新建 Service Fabric 应用程序

然后,使用 .NET Core 2.0 创建一个名为 HelloWorldStateless 的无状态服务项目:Then create a stateless service project using .NET Core 2.0 named HelloWorldStateless:

在第二个对话框中,创建无状态服务项目

解决方案现在包含两个项目:Your solution now contains two projects:

  • HelloWorldHelloWorld. 这是包含服务应用程序项目。This is the application project that contains your services. 它还包含应用程序清单,用于描述该应用程序以及一些帮助你部署应用程序的 PowerShell 脚本。It also contains the application manifest that describes the application, as well as a number of PowerShell scripts that help you to deploy your application.
  • HelloWorldStatelessHelloWorldStateless. 这是服务项目。This is the service project. 其中包含无状态服务实现。It contains the stateless service implementation.

实现服务Implement the service

打开服务项目中的 HelloWorldStateless.cs 文件。Open the HelloWorldStateless.cs file in the service project. 在 Service Fabric 中,服务可以运行任一业务逻辑。In Service Fabric, a service can run any business logic. 服务 API 为代码提供两个入口点:The service API provides two entry points for your code:

  • 名为 RunAsync 的开放式入口点方法,可在其中开始执行任何工作负荷,包括长时间运行的计算工作负荷。An open-ended entry point method, called RunAsync, where you can begin executing any workloads, including long-running compute workloads.

    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        ...
    }
    
  • 一个通信入口点,可在其中插入所选的通信堆栈,例如 ASP.NET Core。A communication entry point where you can plug in your communication stack of choice, such as ASP.NET Core. 这就是可以开始接收来自用户和其他服务请求的位置。This is where you can start receiving requests from users and other services.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        ...
    }
    

在本教程中,我们将重点放在 RunAsync() 入口点方法上。In this tutorial, we will focus on the RunAsync() entry point method. 可在其中立即开始运行代码。This is where you can immediately start running your code. 项目模板包括 RunAsync() 的示例实现,该实现递增滚动计数。The project template includes a sample implementation of RunAsync() that increments a rolling count.

备注

有关如何使用通信堆栈的详细信息,请参阅使用 ASP.NET Core 与服务通信For details about how to work with a communication stack, see Service communication with ASP.NET Core

RunAsyncRunAsync

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    // TODO: Replace the following sample code with your own logic
    //       or remove this RunAsync override if it's not needed in your service.

    long iterations = 0;

    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();

        ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", ++iterations);

        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

当服务实例已放置并且可以执行时,平台将调用此方法。The platform calls this method when an instance of a service is placed and ready to execute. 对于无状态服务,这就意味着打开服务实例。For a stateless service, that simply means when the service instance is opened. 需要关闭服务实例时,将提供取消标记进行协调。A cancellation token is provided to coordinate when your service instance needs to be closed. 在 Service Fabric 中,服务的整个生存期内可能多次出现服务实例的这一打开-关闭循环。In Service Fabric, this open/close cycle of a service instance can occur many times over the lifetime of the service as a whole. 发生这种情况的原因多种多样,包括:This can happen for various reasons, including:

  • 系统可能会移动服务实例以实现资源平衡。The system moves your service instances for resource balancing.
  • 代码中发生错误。Faults occur in your code.
  • 应用程序或系统升级。The application or system is upgraded.
  • 基础硬件遇到中断。The underlying hardware experiences an outage.

系统将管理此业务流程,以便保持服务的高度可用和适当平衡。This orchestration is managed by the system to keep your service highly available and properly balanced.

RunAsync() 不应阻止同步。RunAsync() should not block synchronously. RunAsync 实现应返回 Task,或等待任意长时间运行或阻止的操作以允许运行时继续。Your implementation of RunAsync should return a Task or await on any long-running or blocking operations to allow the runtime to continue. 请注意,上一示例中的 while(true) 循环中使用了返回 Task 的 await Task.Delay()Note in the while(true) loop in the previous example, a Task-returning await Task.Delay() is used. 如果必须同步阻止工作负荷,应使用 RunAsync 实现中的 Task.Run() 安排新的 Task。If your workload must block synchronously, you should schedule a new Task with Task.Run() in your RunAsync implementation.

取消工作负荷是一项由所提供的取消标记协调的协同操作。Cancellation of your workload is a cooperative effort orchestrated by the provided cancellation token. 系统会等待任务结束后(成功完成、取消或出现故障)再执行下一步操作。The system will wait for your task to end (by successful completion, cancellation, or fault) before it moves on. 当系统请求取消时,请务必接受取消标记,完成所有任务,并尽快退出 RunAsync()It is important to honor the cancellation token, finish any work, and exit RunAsync() as quickly as possible when the system requests cancellation.

在此无状态服务示例中,计数存储在本地变量中。In this stateless service example, the count is stored in a local variable. 不过,由于这是无状态服务,因此,所存储的值仅在其所在服务实例的当前生命周期中存在。But because this is a stateless service, the value that's stored exists only for the current lifecycle of its service instance. 当服务移动或重新启动时,值就会丢失。When the service moves or restarts, the value is lost.

创建有状态服务Create a stateful service

Service Fabric 引入了一种新的有状态服务。Service Fabric introduces a new kind of service that is stateful. 有状态服务能够可靠地在服务本身内部保持状态,并与使用它的代码共置。A stateful service can maintain state reliably within the service itself, co-located with the code that's using it. Service Fabric 无需将状态保存到外部存储,便可实现状态的高可用性。State is made highly available by Service Fabric without the need to persist state to an external store.

要将计数器值从无状态转换为即使在服务移动或重新启动时仍高度可用并持久存在,你需要有状态服务。To convert a counter value from stateless to highly available and persistent, even when the service moves or restarts, you need a stateful service.

在同一个 HelloWorld 应用程序中,通过右键单击应用程序项目中的服务引用并选择“添加”->“新建 Service Fabric 服务”,可以添加一个新的服务。In the same HelloWorld application, you can add a new service by right-clicking on the Services references in the application project and selecting Add -> New Service Fabric Service.

向 Service Fabric 应用程序添加服务

选择“.NET Core 2.0”->“有状态服务” 并将其命名为 HelloWorldStateful 。Select .NET Core 2.0 -> Stateful Service and name it HelloWorldStateful. 单击 “确定”Click OK.

使用“新建项目”对话框新建 Service Fabric 有状态服务

应用程序现在应该有两个服务:无状态服务 HelloWorldStateless 和有状态服务 HelloWorldStatefulYour application should now have two services: the stateless service HelloWorldStateless and the stateful service HelloWorldStateful.

有状态服务具有与无状态服务相同的入口点。A stateful service has the same entry points as a stateless service. 主要差异在于可以可靠地存储状态的 状态提供程序 的可用性。The main difference is the availability of a state provider that can store state reliably. Service Fabric 附带名为 Reliable Collections 的状态提供程序实现调用,可让你通过可靠状态管理器创建复制的数据结构。Service Fabric comes with a state provider implementation called Reliable Collections, which lets you create replicated data structures through the Reliable State Manager. 有状态可靠服务默认使用此状态提供程序。A stateful Reliable Service uses this state provider by default.

打开 HelloWorldStateful 中的 HelloWorldStateful.cs,该文件包含以下 RunAsync 方法:Open HelloWorldStateful.cs in HelloWorldStateful, which contains the following RunAsync method:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    // TODO: Replace the following sample code with your own logic
    //       or remove this RunAsync override if it's not needed in your service.

    var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, long>>("myDictionary");

    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();

        using (var tx = this.StateManager.CreateTransaction())
        {
            var result = await myDictionary.TryGetValueAsync(tx, "Counter");

            ServiceEventSource.Current.ServiceMessage(this.Context, "Current Counter Value: {0}",
                result.HasValue ? result.Value.ToString() : "Value does not exist.");

            await myDictionary.AddOrUpdateAsync(tx, "Counter", 0, (key, value) => ++value);

            // If an exception is thrown before calling CommitAsync, the transaction aborts, all changes are
            // discarded, and nothing is saved to the secondary replicas.
            await tx.CommitAsync();
        }

        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }

RunAsyncRunAsync

RunAsync() 在有状态服务和无状态服务中的运行方式类似。RunAsync() operates similarly in stateful and stateless services. 只不过在有状态服务中,平台将先代表用户执行额外的工作,再执行 RunAsync()However, in a stateful service, the platform performs additional work on your behalf before it executes RunAsync(). 这项工作可能包括确保可靠状态管理器和可靠集合随时可供使用。This work can include ensuring that the Reliable State Manager and Reliable Collections are ready to use.

可靠集合与可靠状态管理器Reliable Collections and the Reliable State Manager

var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, long>>("myDictionary");

IReliableDictionary 是一种字典实现,可用于将状态可靠地存储在服务中。IReliableDictionary is a dictionary implementation that you can use to reliably store state in the service. 利用 Service Fabric 和可靠集合,可以将数据直接存储在服务中而无需外部持久性存储。With Service Fabric and Reliable Collections, you can store data directly in your service without the need for an external persistent store. 可靠集合可让数据具备高可用性。Reliable Collections make your data highly available. Service Fabric 通过创建和管理服务的多个 副本 来实现此目的。Service Fabric accomplishes this by creating and managing multiple replicas of your service for you. 它还提供一个抽象 API,消除了管理这些副本及其状态转换所存在的复杂性。It also provides an API that abstracts away the complexities of managing those replicas and their state transitions.

可靠集合可以存储任何 .NET 类型(包括自定义类型),但需要注意以下几点:Reliable Collections can store any .NET type, including your custom types, with a couple of caveats:

  • Service Fabric 通过跨节点复制状态,使状态具备高可用性;而可靠集合会将数据存储到每个副本上的本地磁盘中。Service Fabric makes your state highly available by replicating state across nodes, and Reliable Collections store your data to local disk on each replica. 这意味着可靠集合中存储的所有内容都必须可序列化This means that everything that is stored in Reliable Collections must be serializable. 默认情况下,可靠集合使用 DataContract 进行序列化,因此,在使用默认序列化程序时,务必确保类型受数据协定序列化程序的支持By default, Reliable Collections use DataContract for serialization, so it's important to make sure that your types are supported by the Data Contract Serializer when you use the default serializer.

  • 当你在可靠集合上提交事务时,会复制对象以实现高可用性。Objects are replicated for high availability when you commit transactions on Reliable Collections. 存储在可靠集合中的对象保留在服务的本地内存中。Objects stored in Reliable Collections are kept in local memory in your service. 这意味着对对象进行本地引用。This means that you have a local reference to the object.

    切勿转变这些对象的本地实例而不在事务中的可靠集合上执行更新操作。It is important that you do not mutate local instances of those objects without performing an update operation on the reliable collection in a transaction. 这是因为对对象的本地实例的更改不会自动复制。This is because changes to local instances of objects will not be replicated automatically. 必须将对象重新插回字典中,或在字典上使用其中一个更新方法。You must re-insert the object back into the dictionary or use one of the update methods on the dictionary.

可靠状态管理器会代为管理可靠集合。The Reliable State Manager manages Reliable Collections for you. 在服务中,可随时随地向可靠状态管理器按名称请求可靠集合。You can simply ask the Reliable State Manager for a reliable collection by name at any time and at any place in your service. 可靠状态管理器可确保能取回引用。The Reliable State Manager ensures that you get a reference back. 不建议将对可靠集合实例的引用存储在类成员变量或属性中。We don't recommended that you save references to reliable collection instances in class member variables or properties. 请特别小心,确保在服务生命周期中始终将引用设置为某个实例。Special care must be taken to ensure that the reference is set to an instance at all times in the service lifecycle. 可靠状态管理器会代为处理此工作,且已针对重复访问对其进行优化。The Reliable State Manager handles this work for you, and it's optimized for repeat visits.

事务和异步操作Transactional and asynchronous operations

using (ITransaction tx = this.StateManager.CreateTransaction())
{
    var result = await myDictionary.TryGetValueAsync(tx, "Counter-1");

    await myDictionary.AddOrUpdateAsync(tx, "Counter-1", 0, (k, v) => ++v);

    await tx.CommitAsync();
}

可靠集合具有与其 System.Collections.GenericSystem.Collections.Concurrent 对应项相同的许多操作,但语言集成查询 (LINQ) 除外。Reliable Collections have many of the same operations that their System.Collections.Generic and System.Collections.Concurrent counterparts do, except for Language Integrated Query (LINQ). 可靠集合上的操作是异步的。Operations on Reliable Collections are asynchronous. 这是因为可靠集合的写入操作执行 I/O 操作,以将数据复制并保存到磁盘。This is because write operations with Reliable Collections perform I/O operations to replicate and persist data to disk.

可靠集合操作是 事务性的,因此可以跨多个可靠集合和操作保持状态的一致。Reliable Collection operations are transactional, so that you can keep state consistent across multiple Reliable Collections and operations. 例如,可以在单个事务中,将工作项从 Reliable Queue 取消排队、对其执行操作并将结果保存在 Reliable Dictionary 中。For example, you may dequeue a work item from a Reliable Queue, perform an operation on it, and save the result in a Reliable Dictionary, all within a single transaction. 事务被视为基本操作,它可以保证整个操作要么成功,要么回滚。This is treated as an atomic operation, and it guarantees that either the entire operation will succeed or the entire operation will roll back. 如果将项取消排队之后、保存结果之前发生错误,则会回滚整个事务,并将该项保留在队列中待处理。If an error occurs after you dequeue the item but before you save the result, the entire transaction is rolled back and the item remains in the queue for processing.

运行应用程序Run the application

现在,我们返回到 HelloWorld 应用程序。We now return to the HelloWorld application. 现可生成并部署服务。You can now build and deploy your services. F5 即可生成应用程序并部署到本地群集。When you press F5, your application will be built and deployed to your local cluster.

服务开始运行之后,可以在“诊断事件”窗口中查看生成的 Windows 事件跟踪 (ETW) 事件。After the services start running, you can view the generated Event Tracing for Windows (ETW) events in a Diagnostic Events window. 请注意,应用程序中会同时显示无状态服务和有状态服务的事件。Note that the events displayed are from both the stateless service and the stateful service in the application. 可以通过单击“暂停”按钮来暂停流。You can pause the stream by clicking the Pause button. 然后,可以通过展开该消息来检查消息的详细信息。You can then examine the details of a message by expanding that message.

备注

在运行应用程序之前,请确保正在运行本地开发群集。Before you run the application, make sure that you have a local development cluster running. 有关设置本地环境的信息,请查看入门指南Check out the getting started guide for information on setting up your local environment.

在 Visual Studio 中查看诊断事件

后续步骤Next steps

在 Visual Studio 中调试 Service Fabric 应用程序Debug your Service Fabric application in Visual Studio

入门:Service Fabric Web API 服务与 OWIN 自托管Get started: Service Fabric Web API services with OWIN self-hosting

深入了解 Reliable CollectionsLearn more about Reliable Collections

部署应用程序Deploy an application

应用程序升级Application upgrade

Reliable Services 的开发人员参考Developer reference for Reliable Services