重新整理 .net core 实践篇———承载[外篇]
前言
简单介绍一下承载。
正文
名称叫做承载,其实就是.net core 定义的一套长期运行的服务的规范。
这个服务可以是web服务,也可以是其他服务,比如tcp,或者一些监控服务。
这里以监控服务为例子:
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()
{
return $"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
};
}
internal 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.UtcNow } { PerformanceMetrics.Create() }");
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_scheduler.Dispose();
return Task.CompletedTask;
}
}
然后服务继承IHostedService, 有一个StartAsync 和 StopAsync, 也就是开始和停止服务。
然后在main里面进行注入:
new HostBuilder()
.ConfigureServices(svcs =>
// svcs.AddSingleton<IHostedService, PerformanceMetricsCollector>()
svcs.AddHostedService<PerformanceMetricsCollector>()
)
.Build()
.Run();
这里就是添加这个服务,然后Build,在run 起来就好了。
之所以我们要使用这个HostBuilder,其实就是为了里面帮我们定义的一些依赖注入。
比如一个长期服务需要用到这几个接口:
internal interface IMemoryMetricsCollector
{
long GetUsage();
}
internal interface INetworkMetricsCollector
{
long GetThroughput();
}
internal interface IProcessorMetricsCollector
{
int GetUsage();
}
internal interface IMetricsDeliverer
{
Task DeliverAsync(PerformanceMetrics counters);
}
他们的实现为:
internal class FakeMetricsCollector : IMemoryMetricsCollector, INetworkMetricsCollector, IProcessorMetricsCollector
{
long INetworkMetricsCollector.GetThroughput()
{
return PerformanceMetrics.Create().Network;
}
long IMemoryMetricsCollector.GetUsage()
{
return PerformanceMetrics.Create().Memory;
}
int IProcessorMetricsCollector.GetUsage()
{
return PerformanceMetrics.Create().Processor;
}
}
public class FackMetricsDeliverer : IMetricsDeliverer
{
Task IMetricsDeliverer.DeliverAsync(PerformanceMetrics counter)
{
Console.WriteLine($"{ DateTimeOffset.UtcNow } { counter }");
return Task.CompletedTask;
}
}
然后你的服务就可以这样写:
internal class PerformanceMetricsCollector2 : IHostedService
{
private IDisposable _scheduler;
private readonly IProcessorMetricsCollector _processorMetricsCollector;
private readonly IMemoryMetricsCollector _memoryMetricsCollector;
private readonly INetworkMetricsCollector _networkMetricsCollector;
private readonly IMetricsDeliverer _metricsDeliverer;
public PerformanceMetricsCollector2(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;
}
}
那么在builder的时候,你需要这样写:
var collector = new FakeMetricsCollector();
new HostBuilder()
.ConfigureServices(svcs =>
{
svcs.AddSingleton<IProcessorMetricsCollector>(collector);
svcs.AddSingleton<IMemoryMetricsCollector>(collector);
svcs.AddSingleton<INetworkMetricsCollector>(collector);
svcs.AddSingleton<IMetricsDeliverer, FackMetricsDeliverer>();
svcs.AddHostedService<PerformanceMetricsCollector2>();
})
.Build()
.Run();
这样就可以注入服务了。
有了依赖注入,那么可以做很多事情,比如说配置:
internal class FackMetricsDeliverer3 : IMetricsDeliverer
{
private readonly TransportType _transport;
private readonly EndPoint _deliverTo;
private readonly ILogger _logger;
private readonly Action<ILogger, DateTimeOffset,
PerformanceMetrics, EndPoint, TransportType, Exception> _logForDelivery;
public FackMetricsDeliverer3(IOptions<MetricsCollectionOptions> optionsAccessor,
ILogger<FackMetricsDeliverer3> logger)
{
var options = optionsAccessor.Value;
_transport = options.Transport;
_deliverTo = options.DeliverTo;
_logger = logger;
_logForDelivery = LoggerMessage.Define<DateTimeOffset, PerformanceMetrics,
EndPoint, TransportType>(LogLevel.Information, 0, $"[{0}] Deliver performance counter {1} to {2} via {3}");
}
Task IMetricsDeliverer.DeliverAsync(PerformanceMetrics counters)
{
// Console.WriteLine($"[{DateTimeOffset.Now}] Deliver performance counter {counters} to {_deliverTo} via {_transport}");
_logForDelivery(_logger, DateTimeOffset.UtcNow, counters, _deliverTo, _transport, null);
return Task.CompletedTask;
}
}
然后服务这样写:
internal class PerformanceMetricsCollector3 : IHostedService
{
private IDisposable _scheduler;
private readonly IProcessorMetricsCollector _processorMetricsCollector;
private readonly IMemoryMetricsCollector _memoryMetricsCollector;
private readonly INetworkMetricsCollector _networkMetricsCollector;
private readonly IMetricsDeliverer _metricsDeliverer;
private readonly TimeSpan _captureInterval;
public PerformanceMetricsCollector3(IProcessorMetricsCollector processorMetricsCollector,
IMemoryMetricsCollector memoryMetricsCollector,
INetworkMetricsCollector networkMetricsCollector,
IMetricsDeliverer metricsDeliverer,
IOptions<MetricsCollectionOptions> optionsAccesor)
{
_processorMetricsCollector = processorMetricsCollector;
_memoryMetricsCollector = memoryMetricsCollector;
_networkMetricsCollector = networkMetricsCollector;
_metricsDeliverer = metricsDeliverer;
_captureInterval = optionsAccesor.Value.CaptureInterval;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_scheduler = new Timer(Callback, null, _captureInterval, _captureInterval);
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;
}
}
然后注入的时候这样:
var collector = new FakeMetricsCollector();
new HostBuilder()
.ConfigureAppConfiguration(builder =>
{
builder.AddJsonFile("appSettings.json");
})
.ConfigureServices((context, svcs) =>
{
svcs.AddSingleton<IProcessorMetricsCollector>(collector);
svcs.AddSingleton<IMemoryMetricsCollector>(collector);
svcs.AddSingleton<INetworkMetricsCollector>(collector);
svcs.AddSingleton<IMetricsDeliverer, FackMetricsDeliverer2>();
svcs.AddHostedService<PerformanceMetricsCollector3>();
svcs.AddOptions().Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection"));
})
.Build()
.Run();
就是把appSettings.json进行注入。
这里有了配置之后,还有一个东西需要注意,那就是环境,比如不同的环境加载不同的配置:
new HostBuilder()
// 设置host 环境
.ConfigureHostConfiguration(builder => builder.AddCommandLine(args))
// 设置app 环境
.ConfigureAppConfiguration((context, builder) =>
{
builder.AddJsonFile("appSettings.json", optional: false);
Console.WriteLine(context.HostingEnvironment.EnvironmentName);
builder.AddJsonFile(path: $"appSettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true);
})
.ConfigureServices((context, svcs) =>
{
svcs.AddSingleton<IProcessorMetricsCollector>(collector);
svcs.AddSingleton<IMemoryMetricsCollector>(collector);
svcs.AddSingleton<INetworkMetricsCollector>(collector);
svcs.AddSingleton<IMetricsDeliverer, FackMetricsDeliverer2>();
svcs.AddHostedService<PerformanceMetricsCollector3>();
svcs.AddOptions().Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection"));
})
.Build()
.Run();
有了不同环境不同的配置后,那么你还需要日志:
internal class FackMetricsDeliverer3 : IMetricsDeliverer
{
private readonly TransportType _transport;
private readonly EndPoint _deliverTo;
private readonly ILogger _logger;
private readonly Action<ILogger, DateTimeOffset,
PerformanceMetrics, EndPoint, TransportType, Exception> _logForDelivery;
public FackMetricsDeliverer3(IOptions<MetricsCollectionOptions> optionsAccessor,
ILogger<FackMetricsDeliverer3> logger)
{
var options = optionsAccessor.Value;
_transport = options.Transport;
_deliverTo = options.DeliverTo;
_logger = logger;
_logForDelivery = LoggerMessage.Define<DateTimeOffset, PerformanceMetrics,
EndPoint, TransportType>(LogLevel.Information, 0, $"[{0}] Deliver performance counter {1} to {2} via {3}");
}
Task IMetricsDeliverer.DeliverAsync(PerformanceMetrics counters)
{
// Console.WriteLine($"[{DateTimeOffset.Now}] Deliver performance counter {counters} to {_deliverTo} via {_transport}");
_logForDelivery(_logger, DateTimeOffset.UtcNow, counters, _deliverTo, _transport, null);
return Task.CompletedTask;
}
}
然后配置的时候这样配:
// about log
var collector = new FakeMetricsCollector();
new HostBuilder()
// 设置host 环境
.ConfigureHostConfiguration(builder => builder.AddCommandLine(args))
// 设置app 环境
.ConfigureAppConfiguration((context, builder) => {
builder.AddJsonFile("appSettings.json", optional: false);
Console.WriteLine(context.HostingEnvironment.EnvironmentName);
builder.AddJsonFile(path: $"appSettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true);
})
.ConfigureServices((context, svcs) =>
{
svcs.AddSingleton<IProcessorMetricsCollector>(collector);
svcs.AddSingleton<IMemoryMetricsCollector>(collector);
svcs.AddSingleton<INetworkMetricsCollector>(collector);
svcs.AddSingleton<IMetricsDeliverer, FackMetricsDeliverer3>();
svcs.AddHostedService<PerformanceMetricsCollector3>();
svcs.AddOptions().Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection"));
})
.ConfigureLogging((context , builder)=>
{
builder.AddConfiguration(context.Configuration.GetSection("Logging"));
builder.AddConsole();
})
.Build()
.Run();
这里ConfigureLogging 配置了日志,同样配置了日志的配置。
至此就是一个.net core 定义的一个框架了。
里面有依赖注入、配置、环境、日志。
所以我们依赖这个框架就可以马上专注我们的业务。
下一节看下这种框架是如何设计的。
结
下一节承载的设计。
重新整理 .net core 实践篇———承载[外篇]的更多相关文章
- 重新整理 .net core 实践篇 ———— dotnet-dump [外篇]
前言 本文的上一篇为: https://www.cnblogs.com/aoximin/p/16861797.html 该文为dotnet-dump 和 procdump 的实战介绍一下. 正文 现在 ...
- 重新整理 .net core 实践篇 ———— linux 上线篇 [外篇]
前言 简单整理一个linux 简单上线. 这个是该系列的外篇,该系列继续更新.献给刚学的人. 正文 安装实例 dotnet new webapp -n AspNetCoreDemo -o firstw ...
- 重新整理 .net core 实践篇————配置应用[一]
前言 本来想整理到<<重新整理.net core 计1400篇>>里面去,但是后来一想,整理 .net core 实践篇 是偏于实践,故而分开. 因为是重新整理,那么就从配置开 ...
- 重新整理 .net core 实践篇————依赖注入应用[二]
前言 这里介绍一下.net core的依赖注入框架,其中其代码原理在我的另一个整理<<重新整理 1400篇>>中已经写了,故而专门整理应用这一块. 以下只是个人整理,如有问题, ...
- 重新整理 .net core 实践篇—————Mediator实践[二十八]
前言 简单整理一下Mediator. 正文 Mediator 名字是中介者的意思. 那么它和中介者模式有什么关系呢?前面整理设计模式的时候,并没有去介绍具体的中介者模式的代码实现. 如下: https ...
- 重新整理 .net core 实践篇 ———— linux上排查问题 [外篇]
前言 简单介绍一下在排查问题.献给初学者. 该文的前置篇: https://www.cnblogs.com/aoximin/p/16838657.html 正文 什么是linux系统 linux 是基 ...
- 重新整理 .net core 实践篇 ———— linux上排查问题实用工具 [外篇]
前言 介绍下面几个工具: Lldb createdump dotnet-dump dotnet-gcdump dotnet-symbol Procdump 该文的前置篇为: https://www.c ...
- 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]
前言 该文的前置篇为: https://www.cnblogs.com/aoximin/p/16839830.html 本文介绍性能排查. 正文 上一节是出现错误了,如何去排查具体问题. 这一节介绍一 ...
- 重新整理 .net core 实践篇————依赖注入应用之援军[四]
前言 介绍第三方依赖注入框架Autofac,看看为我们解决什么问题. 下面介绍4个点: 命名注册 属性注册 aop 注入 子容器命名 正文 为什么我们需要使用第三方框架?第三方框架为我们做了什么?第三 ...
- 重新整理 .net core 实践篇—————服务与配置之间[十一二]
前言 前面基本介绍了,官方对于asp .net core 设计配置和设计服务的框架的一些思路.看下服务和配置之间是如何联系的吧. 正文 服务: public interface ISelfServic ...
随机推荐
- 导入Excel文件的时候公式为【#Ref!】应该怎么解决?
前言 在我们使用Excel时,经常会遇到一个问题,就是导入Excel时公式显示为[#Ref!]的情况.这通常是因为公式中引用的单元格已被删除或对应的工作表被删除,导致原公式无法识别对应的参数而显示为[ ...
- nginx设置访问账号密码
第一:为kibana加上了用户登陆访问 第二:不暴露服务器上5601端口,只开放80端口即可.这对服务器的安全也是一个很大的保护. 接下来我们就开始配置nginx与kibana. 一.配置nginx ...
- CTF中常见编码
ASCII编码 ASCII HEX DEC flag{hello_ctfer} 66 6c 61 67 7b 68 65 6c 6c 6f 5f 63 74 66 65 72 7d 102 108 9 ...
- Ayu vscode主题
Ayu vscode主题
- vue-router tomcat 下报404 WEB-INF 放入 web.xml 即可
vue-router tomcat 下报404 WEB-INF 放入 web.xml 即可 <?xml version="1.0" encoding="UTF-8& ...
- python处理txt文件常用方法总结
一 打开txt的正确方式 一般人会用到怎么快速打开txt,下面分享两种方式: f = open("data.txt","r") #设置文件对象 f.close( ...
- linux shell 字体颜色设置
使用 echo -e "\033[0;32;40m" 可以将字体设置成绿色. 这里必须使用echo 的选项 "-e",因为后面需要用到转义序列. 转义序列就是一 ...
- 让艺术触手可及!3DCAT实时云渲染赋能真浪数字艺术馆首展
2023年5月18日,由真浪数字艺术和EZVR联合打造的真浪数字艺术馆首展–「破界·交织」让艺术更自由,正式与大家相见.此次展览分为五个主题展馆,汇聚了来自全球各领域的19位青年数字艺术家一同探讨虚实 ...
- AI助力快速定位数据库难题
最近很多人都在讨论AI能否替代人类工作的话题,最近笔者正好遇到一个AI帮自己快速定位问题的实例,分享给大家,一起来切身感受下AI对于解决数据库问题的价值吧. 事情的经过是这样,有个朋友咨询我,说他最近 ...
- 三维模型3DTile格式轻量化的跨平台兼容性问题分析
三维模型3DTile格式轻量化的跨平台兼容性问题分析 三维模型3DTile格式是一种开放的.高效的和互操作的空间信息数据格式.然而,它作为一种新兴的技术,其在轻量化与跨平台兼容性方面存在着一些问题. ...