.NET Core 3.1之深入源码理解HealthCheck(二)
写在前面
前文讨论了HealthCheck的理论部分,本文将讨论有关HealthCheck的应用内容。
- 可以监视内存、磁盘和其他物理服务器资源的使用情况来了解是否处于正常状态。
- 运行状况检查可以测试应用的依赖项(如数据库和外部服务终结点)以确认是否可用和正常工作。
- 运行状况探测可以由容器业务流程协调程序和负载均衡器用于检查应用的状态。
源码研究
在应用中引入HealthCheck,一般需要配置Startup文件,如下所示:
1: public void ConfigureServices(IServiceCollection services)
2: {
3: services.AddHealthChecks();
4: }
5:
6: public void Configure(IApplicationBuilder app)
7: {
8: app.UseRouting();
9:
10: app.UseEndpoints(endpoints =>
11: {
12: endpoints.MapHealthChecks("/health");
13: });
14: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
其中services.AddHealthChecks();会把我们引入到HealthCheckService的扩展方法中,代码如下:
1: public static class HealthCheckServiceCollectionExtensions
2: {
3: public static IHealthChecksBuilder AddHealthChecks(this IServiceCollection services)
4: {
5: services.TryAddSingleton<HealthCheckService, DefaultHealthCheckService>();
6: services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, HealthCheckPublisherHostedService>());
7: return new HealthChecksBuilder(services);
8: }
9: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
该扩展方法会尝试注册一个HealthCheckService的单例对象。HealthCheckService本身是一个抽象类,它内部含有一个抽象方法,主要用于执行健康检查并返回健康状态的聚合信息。抽象方法如下所示:
1: public abstract Task<HealthReport> CheckHealthAsync(
2: Func<HealthCheckRegistration, bool> predicate,
3: CancellationToken cancellationToken = default);
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
HealthCheckService有一个默认派生类,就是DefaultHealthCheckService,在其构造方法中,会去验证是否有重复的健康检查名称存在,如果有,就会抛出异常。另外名称的检查是不区分大小写的。该类所实现的抽象方法作为健康检查的核心功能,内部实现还是比较复杂的。
首先我们看一下该方法的实现源码:
1: public override async Task<HealthReport> CheckHealthAsync(
2: Func<HealthCheckRegistration, bool> predicate,
3: CancellationToken cancellationToken = default)
4: {
5: var registrations = _options.Value.Registrations;
6: if (predicate != null)
7: {
8: registrations = registrations.Where(predicate).ToArray();
9: }
10:
11: var totalTime = ValueStopwatch.StartNew();
12: Log.HealthCheckProcessingBegin(_logger);
13:
14: var tasks = new Task<HealthReportEntry>[registrations.Count];
15: var index = 0;
16: using (var scope = _scopeFactory.CreateScope())
17: {
18: foreach (var registration in registrations)
19: {
20: tasks[index++] = Task.Run(() => RunCheckAsync(scope, registration, cancellationToken), cancellationToken);
21: }
22:
23: await Task.WhenAll(tasks).ConfigureAwait(false);
24: }
25:
26: index = 0;
27: var entries = new Dictionary<string, HealthReportEntry>(StringComparer.OrdinalIgnoreCase);
28: foreach (var registration in registrations)
29: {
30: entries[registration.Name] = tasks[index++].Result;
31: }
32:
33: var totalElapsedTime = totalTime.GetElapsedTime();
34: var report = new HealthReport(entries, totalElapsedTime);
35: Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime);
36: return report;
37: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
1、其内部有比较完善的监控机制,会在内部维护了一个Log功能,全程监控健康检查的耗时,该日志所记录的健康检查不仅仅是一个健康检查集合的耗时,而且也记录了每个Name的耗时。
2、该方法会通过await Task.WhenAll(tasks).ConfigureAwait(false);并发执行健康检查。当然,我需要注意的是,过多的健康检查任务将会导致系统性能的下降,这主要看如何取舍了
CheckHealthAsync内部还会调用一个私有方法RunCheckAsync,这是真正执行健康检查的方法。RunCheckAsync方法执行完成后,会创建HealthReportEntry对象返回到CheckHealthAsync中,并组装到HealthReport对象中,到此该抽象方法执行完毕。
以下是RunCheckAsync方法的源码:
1: private async Task<HealthReportEntry> RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration, CancellationToken cancellationToken)
2: {
3: cancellationToken.ThrowIfCancellationRequested();
4:
5: var healthCheck = registration.Factory(scope.ServiceProvider);
6:
7: using (_logger.BeginScope(new HealthCheckLogScope(registration.Name)))
8: {
9: var stopwatch = ValueStopwatch.StartNew();
10: var context = new HealthCheckContext { Registration = registration };
11:
12: Log.HealthCheckBegin(_logger, registration);
13:
14: HealthReportEntry entry;
15: CancellationTokenSource timeoutCancellationTokenSource = null;
16: try
17: {
18: HealthCheckResult result;
19:
20: var checkCancellationToken = cancellationToken;
21: if (registration.Timeout > TimeSpan.Zero)
22: {
23: timeoutCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
24: timeoutCancellationTokenSource.CancelAfter(registration.Timeout);
25: checkCancellationToken = timeoutCancellationTokenSource.Token;
26: }
27:
28: result = await healthCheck.CheckHealthAsync(context, checkCancellationToken).ConfigureAwait(false);
29:
30: var duration = stopwatch.GetElapsedTime();
31:
32: entry = new HealthReportEntry(
33: status: result.Status,
34: description: result.Description,
35: duration: duration,
36: exception: result.Exception,
37: data: result.Data,
38: tags: registration.Tags);
39:
40: Log.HealthCheckEnd(_logger, registration, entry, duration);
41: Log.HealthCheckData(_logger, registration, entry);
42: }
43: catch (OperationCanceledException ex) when (!cancellationToken.IsCancellationRequested)
44: {
45: var duration = stopwatch.GetElapsedTime();
46: entry = new HealthReportEntry(
47: status: HealthStatus.Unhealthy,
48: description: "A timeout occured while running check.",
49: duration: duration,
50: exception: ex,
51: data: null);
52:
53: Log.HealthCheckError(_logger, registration, ex, duration);
54: }
55:
56: // Allow cancellation to propagate if it's not a timeout.
57: catch (Exception ex) when (ex as OperationCanceledException == null)
58: {
59: var duration = stopwatch.GetElapsedTime();
60: entry = new HealthReportEntry(
61: status: HealthStatus.Unhealthy,
62: description: ex.Message,
63: duration: duration,
64: exception: ex,
65: data: null);
66:
67: Log.HealthCheckError(_logger, registration, ex, duration);
68: }
69:
70: finally
71: {
72: timeoutCancellationTokenSource?.Dispose();
73: }
74:
75: return entry;
76: }
77: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
来自官方的应用
数据库探测,例子可以是执行 select 1 from
根据数据库响应来判断是否健康
tableNameEntity Framework Core DbContext
探测,DbContext
检查确认应用可以与为 EF CoreDbContext
配置的数据库通信。单独的就绪情况和运行情况探测,在某些托管方案中,可能初始化是一个比较耗时的操作,应用正常运行,但是可能还不能正常处理请求并响应 具有自定义响应编写器的基于指标的探测,比如检查内存占用是否超标,cpu 是否占用过高,连接数是否达到上限 按端口筛选,指定端口,一般用于容器环境,根据容器启动时配置的端口号进行响应 分发运行状况检查库,将检查接口实现独立一个类,并通过依赖注入获取参数,检查时根据参数编写逻辑 运行状况检查发布服务器,如果向 DI 添加
IHealthCheckPublisher,则运行状态检查系统将定期执行状态检查,并使用结果调用
PublishAsync。适用于需要推送的健康系统,而不是健康系统使用 MapWhen 限制运行状况检查,使用 MapWhen
对运行状况检查终结点的请求管道进行条件分支
其他更多内容请参考:https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-3.1
.NET Core 3.1之深入源码理解HealthCheck(二)的更多相关文章
- .NET Core 3.0之深入源码理解Configuration(二)
文件型配置基本内容 上一篇文章讨论了Configuration的几个核心对象,本文继续讨论Configuration中关于文件型配置的相关内容.相比较而言,文件型配置的使用场景更加广泛,用户自定义 ...
- .NET Core 3.0之深入源码理解HttpClientFactory(二)
写在前面 上一篇文章讨论了通过在ConfigureServices中调用services.AddHttpClient()方法,并基于此进一步探讨了DefaultHttpClientFactory是 ...
- .NET Core 3.0之深入源码理解Host(二)
写在前面 停了近一个月的技术博客,随着正式脱离996的魔窟,接下来也正式恢复了.本文从源码角度进一步讨论.NET Core 3.0 中关于Host扩展的一些技术点,主要讨论Long Run Pro ...
- .NET Core 3.0之深入源码理解HealthCheck(一)
写在前面 我们的系统可能因为正在部署.服务异常终止或者其他问题导致系统处于非健康状态,这个时候我们需要知道系统的健康状况,而健康检查可以帮助我们快速确定系统是否处于正常状态.一般情况下,我们会提供公开 ...
- .NET Core 3.0之深入源码理解Startup的注册及运行
原文:.NET Core 3.0之深入源码理解Startup的注册及运行 写在前面 开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程 ...
- .NET Core 3.0之深入源码理解Configuration(三)
写在前面 上一篇文章讨论了文件型配置的基本内容,本篇内容讨论JSON型配置的实现方式,理解了这一种配置类型的实现方式,那么其他类型的配置实现方式基本可以触类旁通.看过了上一篇文章的朋友,应该看得出 ...
- .NET Core 3.0之深入源码理解Configuration(一)
Configuration总体介绍 微软在.NET Core里设计出了全新的配置体系,并以非常灵活.可扩展的方式实现.从其源码来看,其运行机制大致是,根据其Source,创建一个Builder实例,并 ...
- .NET Core 3.0之深入源码理解Kestrel的集成与应用(一)
写在前面 ASP.NET Core 的 Web 服务器默认采用Kestrel,这是一个基于libuv(一个跨平台的基于Node.js异步I/O库)的跨平台.轻量级的Web服务器. 在开始之前,先回 ...
- .NET Core 3.0之深入源码理解Kestrel的集成与应用(二)
前言 前一篇文章主要介绍了.NET Core继承Kestrel的目的.运行方式以及相关的使用,接下来将进一步从源码角度探讨.NET Core 3.0中关于Kestrel的其他内容,该部分内容,我们 ...
随机推荐
- 洛谷P3366 【模板】最小生成树(kuskal)
#include<bits/stdc++.h> using namespace std; ; ; struct node{ int cnt,fa; }f[maxn]; inline voi ...
- Linux中使用gcc编译文件
一个项目中可能有多个cpp文件,在linux下编译执行过程如下: g++ main.cpp distance.cpp ./a.out 即可一起编译两个文件,然后执行该程序.
- react框架下,在页面内加载显示PDF文件,关于react-pdf-js的使用注意事项
react框架下,在页面内加载显示PDF文件,关于react-pdf-js的使用注意事项 之前做了一个需求,在注册账号的时候,让用户同意服务条款, 服务条款是一个PDF文件, 这就需要在react内加 ...
- 杂项-Java-百科:war-un
ylbtech-杂项-Java-百科:war-un 1.返回顶部 1. war是一个可以直接运行的web模块,通常用于网站,打成包部署到容器中.以Tomcat来说,将war包放置在其\webapps\ ...
- oracle不明确的索引等级
当ORACLE无法判断索引的等级高低差别,优化器将只使用一个索引,它就是在WHERE子句中被列在最前面的. 举例: DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引. SELECT ...
- tensorflow入门——5tensorflow安装
你将把你学到的神经网络的知识,借助 TensorFlow ,一个 Google 开源的深度学习框架,应用在真实的数据集中. 你将使用 TensorFlow 来辨别 notMNIST 数据集.它是一个由 ...
- Project Euler Problem 9-Special Pythagorean triplet
我是俩循环暴力 看了看给的文档,英语并不好,有点懵,所以找了个中文的博客看了看:勾股数组学习小记.里面有两个学习链接和例题. import math def calc(): for i in rang ...
- 【已解决】phpMyAdmin中导入mysql数据库文件时出错:您可能正在上传很大的文件,请参考文档来寻找解决办法
期间,用phpMyAdmin去导入90M左右的mysql数据库文件时出错: 您可能正在上传很大的文件,请参考文档来寻找解决方法. [解决过程] 1.很明显,是文件太大,无法导入.即上传文件大小有限制. ...
- 通过git从码云克隆项目到本地
1.下载安装Git,傻瓜式下一步下一步即可... 2.配置Git: 2.1.选择你要clone到本地的路径:右键--->$ Git Bash Here,弹出Linux命令窗口:$ cd ~直接回 ...
- ThinkPHP5.1接收post、get参数
我们要先认识的是请求对象Request类 <?php//要用Request类 第一步就要引入他,才能在当前控制器上使用//知识点:use 与 namespace前面不可有空格等其他操作.name ...