前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET Core 3.0之深入源码理解HealthCheck(一)

.NET Core 3.0之深入源码理解HealthCheck(一)

作者头像
Edison.Ma
发布2020-05-18 15:13:08
6370
发布2020-05-18 15:13:08
举报
文章被收录于专栏:DotNet Core圈圈DotNet Core圈圈

写在前面

我们的系统可能因为正在部署、服务异常终止或者其他问题导致系统处于非健康状态,这个时候我们需要知道系统的健康状况,而健康检查可以帮助我们快速确定系统是否处于正常状态。一般情况下,我们会提供公开的HTTP接口,用于专门化健康检查。

NET Core提供的健康检查库包括Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions和Microsoft.Extensions.Diagnostics.HealthChecks。这两个库共同为我们提供了最基础的健康检查的解决方案,后面扩展的组件主要有下面几个,本文不作其他说明。

AspNetCore.HealthChecks.System AspNetCore.HealthChecks.Network AspNetCore.HealthChecks.SqlServer AspNetCore.HealthChecks.MongoDb AspNetCore.HealthChecks.Npgsql AspNetCore.HealthChecks.Redis AspNetCore.HealthChecks.AzureStorage AspNetCore.HealthChecks.AzureServiceBus AspNetCore.HealthChecks.MySql AspNetCore.HealthChecks.DocumentDb AspNetCore.HealthChecks.SqLite AspNetCore.HealthChecks.Kafka AspNetCore.HealthChecks.RabbitMQ AspNetCore.HealthChecks.IdSvr AspNetCore.HealthChecks.DynamoDB AspNetCore.HealthChecks.Oracle AspNetCore.HealthChecks.Uris

源码探究

Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions是.NET Core健康检查的抽象基础,从中我们可以看出这个库的设计意图。它提供了一个统一的接口IHealthCheck,用于检查应用程序中各个被监控组件的状态,包括后台服务、数据库等。这个接口只有一个方法CheckHealthAsync,

该方法有一个参数是HealthCheckContext,它表示当前健康检查执行时所关联的上下文对象,它的返回值HealthCheckResult表示当前健康检查结束后所产生的被监控组件的运行状态。

源码如下所示:

代码语言:javascript
复制
public interface IHealthCheck
{
    Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default);
}

HealthCheckRegistration

HealthCheckContext里面只有一个成员就是HealthCheckRegistration实例。

HealthCheckRegistration是一个相当重要的对象,它体现了健康检查需要关注和注意的地方,其内部涉及到五个属性,分别用于:

  • 标识健康检查名称
  • 创建IHealthCheck实例
  • 健康检查的超时时间(防止我们因为健康检查而过多占用资源)
  • 失败状态标识
  • 一个标签集合(可用于健康检查过滤)

这五个属性的相关源码如下:

代码语言:javascript
复制
public Func<IServiceProvider, IHealthCheck> Factory
{
    get => _factory;
    set
    {
        if (value == null)
        {
            throw new ArgumentNullException(nameof(value));
        }
    
        _factory = value;
    }
}
    
public HealthStatus FailureStatus { get; set; }
    
public TimeSpan Timeout
{
    get => _timeout;
    set
    {
        if (value <= TimeSpan.Zero && value != System.Threading.Timeout.InfiniteTimeSpan)
        {
            throw new ArgumentOutOfRangeException(nameof(value));
        }
    
        _timeout = value;
    }
}
    
public string Name
{
    get => _name;
    set
    {
        if (value == null)
        {
            throw new ArgumentNullException(nameof(value));
        }
    
        _name = value;
    }
}
    
public ISet<string> Tags { get; }

HealthCheckResult

HealthCheckResult是一个结构体,可以看出这里更多的是基于承担数据存储和性能问题的考量。

HealthCheckResult用于表示健康检查的相关结果信息,同样的,通过该类,我们知道了健康检查需要关注的几个点:

  • 组件的当前状态
  • 异常信息
  • 友好的描述信息(不管是异常还是正常)
  • 额外可描述当前组件的键值对,这是一个开放式的属性,方面我们记录更多信息

该类含有四个公共属性,和三个方法,相关源码如下:

代码语言:javascript
复制

public struct HealthCheckResult
{
    private static readonly IReadOnlyDictionary<string, object> _emptyReadOnlyDictionary = new Dictionary<string, object>();

    public HealthCheckResult(HealthStatus status, string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
    {
        Status = status;
        Description = description;
        Exception = exception;
    Data = data ?? _emptyReadOnlyDictionary;
}

public IReadOnlyDictionary<string, object> Data { get; }

public string Description { get; }

public Exception Exception { get; }

public HealthStatus Status { get; }

public static HealthCheckResult Healthy(string description = null, IReadOnlyDictionary<string, object> data = null)
{
    return new HealthCheckResult(status: HealthStatus.Healthy, description, exception: null, data);
}

public static HealthCheckResult Degraded(string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
{
    return new HealthCheckResult(status: HealthStatus.Degraded, description, exception: exception, data);
}

public static HealthCheckResult Unhealthy(string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
{
    return new HealthCheckResult(status: HealthStatus.Unhealthy, description, exception, data);
}
}

可以看出这个三个方法都是基于HealthStatus这个枚举而创建不同状态的HealthCheckResult实例,这个枚举表达了健康检查需要关注的几种状态,健康、异常以及降级。

HealthStatus的源码如下:

代码语言:javascript
复制
public enum HealthStatus
{
    Unhealthy = 0,
 
    Degraded = 1,
 
    Healthy = 2,
}

IHealthCheckPublisher

健康检查功能本质上是一种轮询功能,需要定期执行,.NET Core 抽象定期执行的接口,即IHealthCheckPublisher,我们可以通过实现这个接口,并与我们自定义的定时功能相结合。

同时,作为一次健康检查,我们还需要关注相关的健康检查报告,那么我们需要关注那些点呢?

  • 额外可描述当前组件的键值对,这是一个开放式的属性,方面我们记录更多信息
  • 友好的描述信息(不管是异常还是正常)
  • 组件的当前状态
  • 异常信息
  • 当前这次检查所耗费的时间
  • 相关的标签信息

HealthReportEntry表示单个健康检查报告,HealthReport表示一组健康检查报告。HealthReport内部维护了一个HealthReportEntry的字典数据,HealthReport源码如下所示:

代码语言:javascript
复制
public sealed class HealthReport
{
    public HealthReport(IReadOnlyDictionary<string, HealthReportEntry> entries, TimeSpan totalDuration)
    {
        Entries = entries;
        Status = CalculateAggregateStatus(entries.Values);
        TotalDuration = totalDuration;
    }

    public IReadOnlyDictionary<string, HealthReportEntry> Entries { get; }

    public HealthStatus Status { get; }

    public TimeSpan TotalDuration { get; }

    private HealthStatus CalculateAggregateStatus(IEnumerable<HealthReportEntry> entries)
    {
        var currentValue = HealthStatus.Healthy;
        foreach (var entry in entries)
        {
            if (currentValue > entry.Status)
            {
                currentValue = entry.Status;
            }

            if (currentValue == HealthStatus.Unhealthy)
            {
                // Game over, man! Game over!
                // (We hit the worst possible status, so there's no need to keep iterating)
                return currentValue;
            }
        }

        return currentValue;
    }
}

总结

通过以上内容,我们知道了,一个完整的健康检查需要关注健康检查上下文、健康状态的维护、健康检查结果、健康检查报告,同时,为了更好的维护健康检查,我们可以将健康检查发布抽象出来,并与外部的定时器相结合,共同守护健康检查程序。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet技术平台 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面
  • 源码探究
    • HealthCheckRegistration
      • HealthCheckResult
        • IHealthCheckPublisher
        • 总结
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档