.NET Core 3.0之深入源码理解HealthCheck(一)
寫在前面
我們的系統可能因為正在部署、服務異常終止或者其他問題導致系統處于非健康狀態,這個時候我們需要知道系統的健康狀況,而健康檢查可以幫助我們快速確定系統是否處于正常狀態。一般情況下,我們會提供公開的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表示當前健康檢查結束后所產生的被監控組件的運行狀態。
源碼如下所示:
public interface IHealthCheck{ Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default);}HealthCheckRegistration
HealthCheckContext里面只有一個成員就是HealthCheckRegistration實例。
而HealthCheckRegistration是一個相當重要的對象,它體現了健康檢查需要關注和注意的地方,其內部涉及到五個屬性,分別用于:
標識健康檢查名稱
創建IHealthCheck實例
健康檢查的超時時間(防止我們因為健康檢查而過多占用資源)
失敗狀態標識
一個標簽集合(可用于健康檢查過濾)
這五個屬性的相關源碼如下:
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用于表示健康檢查的相關結果信息,同樣的,通過該類,我們知道了健康檢查需要關注的幾個點:
組件的當前狀態
異常信息
友好的描述信息(不管是異常還是正常)
額外可描述當前組件的鍵值對,這是一個開放式的屬性,方面我們記錄更多信息
該類含有四個公共屬性,和三個方法,相關源碼如下:
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的源碼如下:
public enum HealthStatus{ Unhealthy = 0, Degraded = 1, Healthy = 2,}IHealthCheckPublisher
健康檢查功能本質上是一種輪詢功能,需要定期執行,.NET Core 抽象定期執行的接口,即IHealthCheckPublisher,我們可以通過實現這個接口,并與我們自定義的定時功能相結合。
同時,作為一次健康檢查,我們還需要關注相關的健康檢查報告,那么我們需要關注那些點呢?
額外可描述當前組件的鍵值對,這是一個開放式的屬性,方面我們記錄更多信息
友好的描述信息(不管是異常還是正常)
組件的當前狀態
異常信息
當前這次檢查所耗費的時間
相關的標簽信息
HealthReportEntry表示單個健康檢查報告,HealthReport表示一組健康檢查報告。HealthReport內部維護了一個HealthReportEntry的字典數據,HealthReport源碼如下所示:
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; }}
總結
通過以上內容,我們知道了,一個完整的健康檢查需要關注健康檢查上下文、健康狀態的維護、健康檢查結果、健康檢查報告,同時,為了更好的維護健康檢查,我們可以將健康檢查發布抽象出來,并與外部的定時器相結合,共同守護健康檢查程序。
總結
以上是生活随笔為你收集整理的.NET Core 3.0之深入源码理解HealthCheck(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++模版和C#泛型求同存异录(一)si
- 下一篇: asp.net ajax控件工具集 Au