[ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇]

2023-12-25 16:48

本文主要是介绍[ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

借助.NET Core提供的承载(Hosting)系统,我们可以将任意一个或者多个长时间运行(Long-Running)的服务寄宿或者承载于托管进程中。ASP.NET Core应用仅仅是该承载系统的一种典型的服务类型而已,任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载。

一、承载长时间运行服务

老幺网 www.laoyao.org

一个ASP.NET Core应用本质上是一个需要长时间运行的服务,开启这个服务是为了启动一个网络监听器。当监听到抵达的HTTP请求之后,该监听器会将请求传递给应用提供的管道进行处理。管道完成了对请求处理之后会生成HTTP响应,并通过监听器返回客户端。除了这种最典型的承载服务,我们还有很多其他的服务承载需求,下面通过一个简单的实例来演示如何承载一个服务来收集当前执行环境的性能指标

我们演示的承载服务会定时采集并分发当前进程的性能指标。简单起见,我们只关注处理器使用率、内存使用量和网络吞吐量这3种典型的性能指标,为此定义了下面的PerformanceMetrics类型。我们并不会实现真正的性能指标收集,所以定义静态方法Create利用随机生成的指标数据创建一个PerformanceMetrics对象。

public class PerformanceMetrics
{private static readonly Random _random = new Random();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 PerformanceMetrics{Processor = _random.Next(1, 8),Memory = _random.Next(10, 100) * 1024 * 1024,Network = _random.Next(10, 100) * 1024 * 1024};
}

承载服务通过IHostedService接口表示,该接口定义的StartAsync方法和StopAsync方法可以启动与关闭服务。我们将性能指标采集服务定义成如下这个实现了该接口的PerformanceMetricsCollector类型。在实现的StartAsync方法中,我们利用Timer创建了一个调度器,每隔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对象。

class Program
{static void Main(){new HostBuilder().ConfigureServices(svcs => svcs.AddSingleton<IHostedService, PerformanceMetricsCollector>()).Build().Run();}
}

在调用Build方法之前,可以调用IHostBuilder接口的ConfigureServices方法将PerformancceMetricsCollector注册成针对IHostedService接口的服务,并将生命周期模式设置成Singleton。除了采用普通的依赖服务注册方式,针对IHostedService服务的注册还可以调用IServiceCollection接口的AddHostedService<THostedService>扩展方法来完成,如下所示的编程方式与上面是完全等效的。

class Program
{static void Main(){new HostBuilder().ConfigureServices(svcs => svcs.AddHostedService<PerformanceMetricsCollector>()).Build().Run();}
}

最后调用Run方法启动通过IHost对象表示的承载服务宿主,进而启动由它承载的PerformancceMetricsCollector服务,该服务将以下图所示的形式每隔5秒显示由它“采集”的性能指标。(源代码从这里下载)

10-1

二、依赖注入

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

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

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

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

由于整个性能指标的采集工作被分解到4个接口表示的服务之中,所以可以采用如下所示的方式重新定义承载服务类型PerformanceMetricsCollector。如下面的代码片段所示,可以直接在构造函数中注入4个依赖服务。对于在StartAsync方法创建的调用器来说,它会利用3个对应的服务采集3种类型的性能指标,并利用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方法进行注册,我们采用如下方式注册了作为承载服务的PerformanceMetricsCollector和它依赖的4个服务。修改后的程序启动之后同样会在控制台上看到上面图片所示的输出结果。(源代码从这里下载)

class Program
{static void Main(){var collector = new FakeMetricsCollector();new HostBuilder().ConfigureServices(svcs => svcs  .AddSingleton<IProcessorMetricsCollector>(collector).AddSingleton<IMemoryMetricsCollector>(collector).AddSingleton<INetworkMetricsCollector>(collector).AddSingleton<IMetricsDeliverer, FakeMetricsDeliverer>().AddSingleton<IHostedService, PerformanceMetricsCollector>()).Build().Run();}
}

服务承载系统[1]: 承载长时间运行的服务[上篇]
服务承载系统[2]: 承载长时间运行的服务[下篇]
服务承载系统[3]: 服务承载模型[上篇]
服务承载系统[4]: 服务承载模型[下篇]
服务承载系统[5]: 承载服务启动流程[上篇]
服务承载系统[6]: 承载服务启动流程[下篇]

这篇关于[ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/536217

相关文章

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

Linux系统之lvcreate命令使用解读

《Linux系统之lvcreate命令使用解读》lvcreate是LVM中创建逻辑卷的核心命令,支持线性、条带化、RAID、镜像、快照、瘦池和缓存池等多种类型,实现灵活存储资源管理,需注意空间分配、R... 目录lvcreate命令详解一、命令概述二、语法格式三、核心功能四、选项详解五、使用示例1. 创建逻

Python Web框架Flask、Streamlit、FastAPI示例详解

《PythonWeb框架Flask、Streamlit、FastAPI示例详解》本文对比分析了Flask、Streamlit和FastAPI三大PythonWeb框架:Flask轻量灵活适合传统应用... 目录概述Flask详解Flask简介安装和基础配置核心概念路由和视图模板系统数据库集成实际示例Stre

MySQL多实例管理如何在一台主机上运行多个mysql

《MySQL多实例管理如何在一台主机上运行多个mysql》文章详解了在Linux主机上通过二进制方式安装MySQL多实例的步骤,涵盖端口配置、数据目录准备、初始化与启动流程,以及排错方法,适用于构建读... 目录一、什么是mysql多实例二、二进制方式安装MySQL1.获取二进制代码包2.安装基础依赖3.清

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1

Olingo分析和实践之OData框架核心组件初始化(关键步骤)

《Olingo分析和实践之OData框架核心组件初始化(关键步骤)》ODataSpringBootService通过初始化OData实例和服务元数据,构建框架核心能力与数据模型结构,实现序列化、URI... 目录概述第一步:OData实例创建1.1 OData.newInstance() 详细分析1.1.1

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三

RabbitMQ消息总线方式刷新配置服务全过程

《RabbitMQ消息总线方式刷新配置服务全过程》SpringCloudBus通过消息总线与MQ实现微服务配置统一刷新,结合GitWebhooks自动触发更新,避免手动重启,提升效率与可靠性,适用于配... 目录前言介绍环境准备代码示例测试验证总结前言介绍在微服务架构中,为了更方便的向微服务实例广播消息,

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序