Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Azure Service Fabric 应用程序包含一个或多个运行代码的服务。 本指南说明如何使用 Reliable Services 同时创建无状态与有状态的 Service Fabric 应用程序。
查看此页面,观看还将介绍如何创建无状态 Reliable Services 的培训视频。
基本概念
了解几个基本概念,即可开始使用 Reliable Services:
-
服务类型:这是你的服务实现。 它由你编写的类定义,该类将扩展
StatelessService以及其中使用的任何其他代码或依赖项以及名称和版本号。 - 命名服务实例:若要运行服务,需要创建服务类型的命名实例,就像创建类类型的对象实例一样。 服务实例具有使用“fabric:/”方案(如“fabric:/MyApp/MyService”)的 URI 形式的名称。
- 服务主机:创建的命名服务实例需要在主机进程内运行。 服务宿主进程是运行服务实例的一个进程。
- 服务注册:通过注册可将所有对象融合在一起。 要让 Service Fabric 能够创建可运行的实例,必须在服务宿主中将服务类型注册到 Service Fabric 运行时。
创建无状态服务
无状态服务是目前在云应用程序中作为基准的服务类型。 它被视为无状态,因为服务本身不包含需要可靠地存储或高度可用的数据。 如果无状态服务的实例关闭,其所有内部状态都会丢失。 在这种类型的服务中,必须将状态保存到外部存储(如 Azure 表或 SQL 数据库),才能实现高可用性和可靠性。
以管理员身份启动 Visual Studio 2017 或 Visual Studio 2019,并新建一个名为 HelloWorld 的 Service Fabric 应用程序项目:
然后,使用 .NET Core 2.0 创建一个名为 HelloWorldStateless 的无状态服务项目:
解决方案现在包含两个项目:
- HelloWorld。 这是包含服务的应用程序项目。 它还包含应用程序清单,用于描述该应用程序以及一些帮助你部署应用程序的 PowerShell 脚本。
- HelloWorldStateless。 这是服务项目。 其中包含无状态服务实现。
实施服务
打开服务项目中的 HelloWorldStateless.cs 文件。 在 Service Fabric 中,服务可以运行任一业务逻辑。 服务 API 为代码提供两个入口点:
- 名为 RunAsync 的开放式入口点方法,可在其中开始执行任何工作负荷,包括长时间运行的计算工作负荷。
protected override async Task RunAsync(CancellationToken cancellationToken)
{
...
}
- 一个通信入口点,可在其中插入所选的通信堆栈,例如 ASP.NET Core。 这就是您可以开始接收用户和其他服务请求的地方。
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
...
}
在本教程中,我们将重点放在 RunAsync() 入口点方法上。 这是可以立即开始运行代码的位置。
项目模板包括 RunAsync() 的示例实现,该实现递增滚动计数。
注意
有关如何使用通信堆栈的详细信息,请参阅使用 ASP.NET Core 与服务通信
RunAsync
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);
}
}
当服务实例已放置并且可以执行时,平台将调用此方法。 对于无状态服务,这意味着当服务实例被打开时。 当您的服务实例需要关闭时,将提供取消令牌以进行协调。 在 Service Fabric 中,服务的整个生存期内可能多次出现服务实例的这一打开-关闭循环。 发生这种情况的原因多种多样,包括:
- 系统会移动服务实例以实现资源平衡。
- 代码中发生错误。
- 应用程序或系统升级。
- 基础硬件遇到中断。
系统将管理此业务流程,以便保持服务的高度可用和适当平衡。
RunAsync() 不应以同步方式阻塞。 RunAsync 实现应返回 Task,或等待任意长时间运行或阻止的操作以允许运行时继续。 请注意,上一示例中的 while(true) 循环中使用了返回 Task 的 await Task.Delay()。 如果必须同步阻止工作负荷,应使用 Task.Run() 实现中的 RunAsync 安排新的 Task。
取消工作负荷是一项由所提供的取消标记协调的协同操作。 系统会等任务结束后(成功完成、取消或出现故障)再执行下一步操作。 请务必遵循取消令牌、完成任何工作,并在系统请求取消时尽快退出 RunAsync() 。
在此无状态服务示例中,计数存储在本地变量中。 不过,由于这是无状态服务,因此,所存储的值仅在其所在服务实例的当前生命周期中存在。 当服务移动或重新启动时,值就会丢失。
创建有状态服务
Service Fabric 引入了一种新的有状态服务。 有状态服务能够在服务内部可靠地存储状态,并与调用它的代码共同存放。 Service Fabric 无需将状态保存到外部存储,便可实现状态的高可用性。
要将计数器值从无状态转换为高度可用且持久存储状态,即使在服务移动或重新启动时也是如此,你需要使用有状态服务。
在同一个 HelloWorld 应用程序中,通过右键单击应用程序项目中的服务引用并选择“添加”->“新建 Service Fabric 服务”,可以添加一个新的服务。
选择 .NET Core 2.0 - 有状态服务>,并将其命名为 HelloWorldStateful。 单击“确定” 。
应用程序现在应该有两个服务:无状态服务 HelloWorldStateless 和有状态服务 HelloWorldStateful。
有状态服务具有与无状态服务相同的入口点。 主要区别是是否有能够可靠地存储状态的状态提供程序。 Service Fabric 附带名为可靠集合的状态提供程序实现,可让你通过可靠状态管理器创建复制的数据结构。 有状态可靠服务默认使用此状态提供程序。
打开 HelloWorldStateful 中的 HelloWorldStateful.cs,该文件包含以下 RunAsync 方法:
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);
}
RunAsync
RunAsync() 在有状态服务和无状态服务中的运行方式类似。 只不过在有状态服务中,平台将先代表用户执行额外的工作,再执行 RunAsync()。 这项工作可能包括确保可靠状态管理器和可靠集合随时可供使用。
可靠集合与可靠状态管理器
var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, long>>("myDictionary");
IReliableDictionary 是一种字典实现,可用于将状态可靠地存储在服务中。 利用 Service Fabric 和可靠集合,可以将数据直接存储在服务中而无需外部持久性存储。 可靠集合可让数据具备高可用性。 Service Fabric 通过创建和管理服务的多个副本来实现此目的。 它还提供一个抽象 API,消除了管理这些副本及其状态转换所存在的复杂性。
可靠集合可以存储任何 .NET 类型(包括自定义类型),但需要注意以下几点:
Service Fabric 通过跨节点复制状态,使状态具备高可用性;而可靠集合会将数据存储到每个副本上的本地磁盘中。 这意味着可靠集合中存储的所有内容都必须可序列化。 默认情况下,可靠集合使用 DataContract 进行序列化,因此,在使用默认序列化程序时,务必确保类型受数据协定序列化程序的支持。
在可靠集合中提交事务时,会复制对象以确保高可用性。 存储在可靠集合中的对象保留在服务的本地内存中。 这意味着你有对该对象的本地引用。
请务必不要在事务中对可靠集合执行更新操作之前更改这些对象的本地实例。 这是因为对对象的本地实例的更改将不会自动复制。 必须将对象重新插回字典中,或在字典上使用其中一个更新方法。
可靠状态管理器为您管理可靠集合对象。 无论何时何地,都可以根据名称向可靠状态管理器请求服务中的某个可靠集合。 可靠状态管理器可确保能取回引用。 不建议将可靠集合实例的引用存储在类成员变量或属性中。 在服务生命周期的任何时候,都必须特别注意确保引用始终设置为一个实例。 可靠状态管理器会代为处理此工作,且已针对重复访问对其进行优化。
事务和异步操作
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.Generic 和 System.Collections.Concurrent 对应项相同的许多操作,但语言集成查询 (LINQ) 除外。 可靠集合中的操作通常是异步的。 这是因为可靠集合的写入操作执行 I/O 操作,以将数据复制并保存到磁盘。
可靠集合操作是事务性的,因此可以跨多个可靠集合和操作保持状态的一致。 例如,可以在单个事务中,将工作项从 Reliable Queue 取消排队、对其执行操作并将结果保存在 Reliable Dictionary 中。 这被视为原子操作,它可以保证整个操作要么成功,要么回滚。 如果在将项出队列后、保存结果前发生错误,则整个事务会回滚,且项将保留在队列中以供处理。
运行应用程序
现在,我们返回到 HelloWorld 应用程序。 现在,可以生成并部署服务。 按 F5 即可生成应用程序并部署到本地群集。
服务开始运行之后,可以在“诊断事件”窗口中查看生成的 Windows 事件跟踪 (ETW) 事件。 请注意,应用程序中会同时显示无状态服务和有状态服务的事件。 可以通过单击“暂停”按钮来暂停流。 然后,可以通过展开该消息来检查消息的详细信息。
注意
在运行应用程序之前,请确保正在运行本地开发群集。 有关设置本地环境的信息,请查看入门指南。
后续步骤
在 Visual Studio 中调试 Service Fabric 应用程序