您现在的位置是:网站首页> 编程资料编程资料

ASP.NET Core 6框架揭秘实例演示之如何承载你的后台服务_实用技巧_

2023-05-24 355人已围观

简介 ASP.NET Core 6框架揭秘实例演示之如何承载你的后台服务_实用技巧_

借助 .NET提供的服务承载(Hosting)系统,我们可以将一个或者多个长时间运行的后台服务寄宿或者承载我们创建的应用中。任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载,ASP.NET Core应用最终也体现为这样一个承载服务。

借助 .NET提供的服务承载(Hosting)系统,我们可以将一个或者多个长时间运行的后台服务寄宿或者承载我们创建的应用中。任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载,ASP.NET Core应用最终也体现为这样一个承载服务。(本篇提供的实例已经汇总到《ASP.NET Core 6框架揭秘-实例演示版》)

[S1401]利用承载服务收集性能指标

承载服务的项目一般会采用“Microsoft.NET.Sdk.Worker”这个SDK。服务承载模型涉及的接口和类型大都定义在“Microsoft.Extensions.Hosting.Abstractions”这个NuGet包,而具体实现在由NuGet包“Microsoft.Extensions.Hosting”来提供。我们演示的承载服务会定时采集当前进程的性能指标并将其分发出去。我们只关注处理器使用率、内存使用量和网络吞吐量这三种典型的指标,为此我们定义了如下这个PerformanceMetrics类型。我们并不会实现真正的性能指标收集,定义的静态方法Create会利用随机生成的指标来创建PerformanceMetrics对象。

public class PerformanceMetrics { private static readonly Random _random = new(); public int Processor { get; set; } public long Memory { get; set; } public long Network { get; set; } public override string ToString() => @$"CPU: {Processor * 100}%; Memory: {Memory / (1024* 1024)}M; Network: {Network / (1024 * 1024)}M/s"; public static PerformanceMetrics Create() => new() { Processor = _random.Next(1, 8), Memory = _random.Next(10, 100) * 1024 * 1024, Network = _random.Next(10, 100) * 1024 * 1024 }; }

承载服务通过IHostedService接口表示,该接口定义的StartAsync和StopAsync方法可以启动与关闭服务。我们将性能指标采集服务定义成如下这个PerformanceMetricsCollector类型。在实现的StartAsync方法中,我们一个定时器每隔5秒调用Create方法创建一个PerformanceMetrics对象,并将它承载的性能指标输出到控制台上。作为定期是的Timer对象会在StopAsync方法中被释放。

public sealed class PerformanceMetricsCollector : IHostedService { private IDisposable? _scheduler; public Task StartAsync(CancellationToken cancellationToken) { _scheduler = new Timer(Callback, null, TimeSpan.FromSeconds(5),TimeSpan.FromSeconds(5)); return Task.CompletedTask; static void Callback(object? state)=> Console.WriteLine($"[{DateTimeOffset.Now}]{PerformanceMetrics.Create()}"); } public Task StopAsync(CancellationToken cancellationToken) { _scheduler?.Dispose(); return Task.CompletedTask; } }

服务承载系统通过IHost接口表示承载服务的宿主,该对象在应用启动过程中采用Builder模式由对应的IHostBuilder对象来构建。HostBuilder类型是对IHostBuilder接口的默认实现,所以我们采用如下方式创建一个HostBuilder对象,并调用其Build方法来提供作为宿主的IHost对象。在调用Build方法构建IHost对象之前,我们调用了ConfigureServices方法将PerformancceMetricsCollector注册成针对IHostedService接口的服务,并将生命周期模式设置成Singleton。

using App; new HostBuilder() .ConfigureServices(svcs => svcs .AddSingleton()) .Build() .Run();

我们最后调用Run方法启动通过IHost对象表示的承载服务宿主,进而启动由它承载的PerformancceMetricsCollector服务,该服务将以图1所示的形式每隔5秒在控制台上输出“采集”的性能指标。

图1 承载指标采集服务

除了采用一般的服务注册方式,我们还可以按照如下的方式调用IServiceCollection接口的AddHostedService扩展方法来对承载服务PerformanceMetricsCollector进行注册。我们一般也不会通过调用构造函数的方式创建HostBuilder对象,而是使用定义在Host类型中的 工厂方法CreateDefaultBuilder创建来构建IHostBuilder对象。

using App; Host.CreateDefaultBuilder(args) .ConfigureServices(svcs => svcs.AddHostedService()) .Build() .Run();

[S1402]依赖注入的应用

服务承载系统整合依赖注入框架,针对承载服务的注册实际上就是将它注册到依赖注入框架中。既然承载服务实例最终是通过依赖注入容器提供的,那么它自身所依赖的服务当然也可以进行注册。我们接下来将PerformanceMetricsCollector提供的性能指标收集功能分解到由四个接口表示的服务中,IProcessorMetricsCollector、IMemoryMetricsCollector和INetworkMetricsCollector接口代表的服务分别用于收集三种对应的性能指标,而IMetricsDeliverer接口表示的服务则负责将收集的性能指标发送出去。

public interface IProcessorMetricsCollector { int GetUsage(); } public interface IMemoryMetricsCollector { long GetUsage(); } public interface INetworkMetricsCollector { long GetThroughput(); } public interface IMetricsDeliverer { Task DeliverAsync(PerformanceMetrics counter); }

我们定义的MetricsCollector类型实现了三个性能指标采集接口,采集的性能指标直接来源于通过静态方法Create创建的PerformanceMetrics对象。MetricsDeliverer类型实现了IMetricsDeliverer接口,实现的DeliverAsync方法直接将PerformanceMetrics对象承载的性能指标输出到控制台上。

public class MetricsCollector : IProcessorMetricsCollector, IMemoryMetricsCollector, INetworkMetricsCollector { long INetworkMetricsCollector.GetThroughput() => PerformanceMetrics.Create().Network; int IProcessorMetricsCollector.GetUsage() => PerformanceMetrics.Create().Processor; long IMemoryMetricsCollector.GetUsage() => PerformanceMetrics.Create().Memory; } public class MetricsDeliverer : IMetricsDeliverer { public Task DeliverAsync(PerformanceMetrics counter) { Console.WriteLine($"[{DateTimeOffset.UtcNow}]{counter}"); return Task.CompletedTask; } }

由于整个性能指标的采集工作被分解到四个接口表示的服务之中,所以我们可以采用如下所示的方式重新定义承载服务类型PerformanceMetricsCollector。如代码片段所示,我们在构造函数中注入四个依赖服务,StartAsync方法利用注入的IProcessorMetricsCollector、IMemoryMetricsCollector和INetworkMetricsCollector对象采集对应的性能指标,并利用IMetricsDeliverer对象将其发送出去。

public sealed class PerformanceMetricsCollector : IHostedService { private readonly IProcessorMetricsCollector _processorMetricsCollector; private readonly IMemoryMetricsCollector _memoryMetricsCollector; private readonly INetworkMetricsCollector _networkMetricsCollector; private readonly IMetricsDeliverer _MetricsDeliverer; private IDisposable? _scheduler; public PerformanceMetricsCollector( IProcessorMetricsCollector processorMetricsCollector, IMemoryMetricsCollector memoryMetricsCollector, INetworkMetricsCollector networkMetricsCollector, IMetricsDeliverer MetricsDeliverer) { _processorMetricsCollector = processorMetricsCollector; _memoryMetricsCollector = memoryMetricsCollector; _networkMetricsCollector = networkMetricsCollector; _MetricsDeliverer = MetricsDeliverer; } public Task StartAsync(CancellationToken cancellationToken) { _scheduler = new Timer(Callback, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)); return Task.CompletedTask; async void Callback(object? state) { var counter = new PerformanceMetrics { Processor = _processorMetricsCollector.GetUsage(), Memory = _memoryMetricsCollector.GetUsage(), Network = _networkMetricsCollector.GetThroughput() }; await _MetricsDeliverer.DeliverAsync(counter); } } public Task StopAsync(CancellationToken cancellationToken) { _scheduler?.Dispose(); return Task.CompletedTask; } }

在调用IHostBuilder接口的Build方法将IHost对象构建出来之前,包括承载服务在内的所有服务都可以通过它的ConfigureServices方法进行了注册。修改后的程序启动之后同样会在控制台上看到图14-1所示的输出结果(S1402)。

using App; var collector = new MetricsCollector(); Host.CreateDefaultBuilder(args) .ConfigureServices(svcs => svcs .AddHostedService() .AddSingleton(collector) .AddSingleton(collector) .AddSingleton(collector) .AddSingleton()) .Build() .Run();

[S1403]配置选项的应用

真正的应用开发基本都会使用到配置选项,比如我们演示程序中性能指标采集的时间间隔就应该采用配置选项来指定。由于涉及对性能指标数据的发送,所以最好将发送的目标地址定义在配置选项中。如果有多种传输协议可供选择,就可以定义相应的配置选项。 .NET应用推荐采用Options模式来使用配置选项,所以可以定义如下这个MetricsCollectionOptions类型来承载三种配置选项。

public class MetricsCollectionOptions { public TimeSpan CaptureInterval { get; set; } public TransportType Transport { get; set; } public Endpoint DeliverTo { get; set; } } public enum TransportType { Tcp, Http, Udp } public class Endpoint { public string Host { get; set; } public int Port { get; set; } public override string ToString() => $"{Host}:{Port}"; }

传输协议和目标地址使用在MetricsDeliverer服务中,所以我们对它进行了如下的修改。如代码片段所示,我们在构造函数中利用注入的IOptions服务来提供上面的两个配置选项。在实现的DeliverAsync方法中,我们将采用的传输协议和目标地址输出到控制台上。

public class MetricsDeliverer : IMetricsDeliverer { private readonly TransportType _transport; private readonly Endpoint _deliverTo; public MetricsDeliverer(IOptions optionsAccessor) { var options = optionsAccessor.Value; _transport = options.Transport; _deliverTo = options.DeliverTo; } public Task DeliverAsync(PerformanceMetrics counter) { Console.WriteLine($"[{DateTimeOffset.Now}]Deliver performance counter {counter} to {_deliverTo} via {_transport}"); return Task.CompletedTask; } }

承载服务类型PerformanceMetricsCollector同样应该采用这种方式来提取表示性能指标采集频率的配置选项。如下所示的代码片段是PerformanceMetricsCollector采用配置选项后的完整定义。

public sealed class PerformanceMetricsCollector : IHostedService { private readonly IProcessorMetricsCollector _processorMetricsCollector; private readonly IMemoryMetricsCollector _memoryMetricsCollector; private readonly INetworkMetricsCollector _networkMetricsCollector; private readonly IMetricsDeliverer _metricsDeliverer; private readonly TimeSpan _captureInterval; private IDisposable? _scheduler; public PerformanceMetricsCollector( IProcessorMetricsCollector processorMetricsCollector, IMemoryMetricsCollector memoryMetricsCollector, INetworkMetricsCollector networkMetricsCollector, IMetricsDeliverer metricsDeliverer, IOptions optionsAccessor) { _processorMetricsCollector = processorMetricsCollector; _memoryMetricsCollector = memoryMetricsCollector; _networkMetricsCollector = networkMetricsCollector; _metricsDeliverer = metricsDeliverer; _captureInterval = optionsAccessor.Value.CaptureInterv
                
                

-六神源码网