博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET Core 3.1之深入源码理解HealthCheck(二)
阅读量:4032 次
发布时间:2019-05-24

本文共 6262 字,大约阅读时间需要 20 分钟。

写在前面

前文讨论了HealthCheck的理论部分,本文将讨论有关HealthCheck的应用内容。

  • 可以监视内存、磁盘和其他物理服务器资源的使用情况来了解是否处于正常状态。

  • 运行状况检查可以测试应用的依赖项(如数据库和外部服务终结点)以确认是否可用和正常工作。

  • 运行状况探测可以由容器业务流程协调程序和负载均衡器用于检查应用的状态。

源码研究

在应用中引入HealthCheck,一般需要配置Startup文件,如下所示:

public void ConfigureServices(IServiceCollection services){    services.AddHealthChecks();}public void Configure(IApplicationBuilder app){    app.UseRouting();    app.UseEndpoints(endpoints =>    {        endpoints.MapHealthChecks("/health");    });}

其中services.AddHealthChecks();会把我们引入到HealthCheckService的扩展方法中,代码如下:

public static class HealthCheckServiceCollectionExtensions{    public static IHealthChecksBuilder AddHealthChecks(this IServiceCollection services)    {        services.TryAddSingleton
(); services.TryAddEnumerable(ServiceDescriptor.Singleton
()); return new HealthChecksBuilder(services); }}

该扩展方法会尝试注册一个HealthCheckService的单例对象。HealthCheckService本身是一个抽象类,它内部含有一个抽象方法,主要用于执行健康检查并返回健康状态的聚合信息。抽象方法如下所示:

public abstract Task
CheckHealthAsync( Func
predicate, CancellationToken cancellationToken = default);

HealthCheckService有一个默认派生类,就是DefaultHealthCheckService,在其构造方法中,会去验证是否有重复的健康检查名称存在,如果有,就会抛出异常。另外名称的检查是不区分大小写的。该类所实现的抽象方法作为健康检查的核心功能,内部实现还是比较复杂的。

首先我们看一下该方法的实现源码:

public override async Task
CheckHealthAsync( Func
predicate, CancellationToken cancellationToken = default){ var registrations = _options.Value.Registrations; if (predicate != null) { registrations = registrations.Where(predicate).ToArray(); } var totalTime = ValueStopwatch.StartNew(); Log.HealthCheckProcessingBegin(_logger); var tasks = new Task
[registrations.Count]; var index = 0; using (var scope = _scopeFactory.CreateScope()) { foreach (var registration in registrations) { tasks[index++] = Task.Run(() => RunCheckAsync(scope, registration, cancellationToken), cancellationToken); } await Task.WhenAll(tasks).ConfigureAwait(false); } index = 0; var entries = new Dictionary
(StringComparer.OrdinalIgnoreCase); foreach (var registration in registrations) { entries[registration.Name] = tasks[index++].Result; } var totalElapsedTime = totalTime.GetElapsedTime(); var report = new HealthReport(entries, totalElapsedTime); Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime); return report;}

1、其内部有比较完善的监控机制,会在内部维护了一个Log功能,全程监控健康检查的耗时,该日志所记录的健康检查不仅仅是一个健康检查集合的耗时,而且也记录了每个Name的耗时。

2、该方法会通过await Task.WhenAll(tasks).ConfigureAwait(false);并发执行健康检查。当然,我需要注意的是,过多的健康检查任务将会导致系统性能的下降,这主要看如何取舍了

CheckHealthAsync内部还会调用一个私有方法RunCheckAsync,这是真正执行健康检查的方法。RunCheckAsync方法执行完成后,会创建HealthReportEntry对象返回到CheckHealthAsync中,并组装到HealthReport对象中,到此该抽象方法执行完毕。

以下是RunCheckAsync方法的源码:

private async Task
RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration, CancellationToken cancellationToken){ cancellationToken.ThrowIfCancellationRequested(); var healthCheck = registration.Factory(scope.ServiceProvider); using (_logger.BeginScope(new HealthCheckLogScope(registration.Name))) { var stopwatch = ValueStopwatch.StartNew(); var context = new HealthCheckContext { Registration = registration }; Log.HealthCheckBegin(_logger, registration); HealthReportEntry entry; CancellationTokenSource timeoutCancellationTokenSource = null; try { HealthCheckResult result; var checkCancellationToken = cancellationToken; if (registration.Timeout > TimeSpan.Zero) { timeoutCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); timeoutCancellationTokenSource.CancelAfter(registration.Timeout); checkCancellationToken = timeoutCancellationTokenSource.Token; } result = await healthCheck.CheckHealthAsync(context, checkCancellationToken).ConfigureAwait(false); var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: result.Status, description: result.Description, duration: duration, exception: result.Exception, data: result.Data, tags: registration.Tags); Log.HealthCheckEnd(_logger, registration, entry, duration); Log.HealthCheckData(_logger, registration, entry); } catch (OperationCanceledException ex) when (!cancellationToken.IsCancellationRequested) { var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: HealthStatus.Unhealthy, description: "A timeout occured while running check.", duration: duration, exception: ex, data: null); Log.HealthCheckError(_logger, registration, ex, duration); } // Allow cancellation to propagate if it's not a timeout. catch (Exception ex) when (ex as OperationCanceledException == null) { var duration = stopwatch.GetElapsedTime(); entry = new HealthReportEntry( status: HealthStatus.Unhealthy, description: ex.Message, duration: duration, exception: ex, data: null); Log.HealthCheckError(_logger, registration, ex, duration); } finally { timeoutCancellationTokenSource?.Dispose(); } return entry; }}

来自官方的应用

  • 数据库探测,例子可以是执行select 1 from tableName根据数据库响应来判断是否健康

  • Entity Framework Core DbContext 探测,DbContext 检查确认应用可以与为 EF Core DbContext 配置的数据库通信。

  • 单独的就绪情况和运行情况探测,在某些托管方案中,可能初始化是一个比较耗时的操作,应用正常运行,但是可能还不能正常处理请求并响应

  • 具有自定义响应编写器的基于指标的探测,比如检查内存占用是否超标,cpu 是否占用过高,连接数是否达到上限

  • 按端口筛选,指定端口,一般用于容器环境,根据容器启动时配置的端口号进行响应

  • 分发运行状况检查库,将检查接口实现独立一个类,并通过依赖注入获取参数,检查时根据参数编写逻辑

  • 运行状况检查发布服务器,如果向 DI 添加 IHealthCheckPublisher,则运行状态检查系统将定期执行状态检查,并使用结果调用 PublishAsync。适用于需要推送的健康系统,而不是健康系统

  • 使用 MapWhen 限制运行状况检查,使用 MapWhen 对运行状况检查终结点的请求管道进行条件分支

其他更多内容请参考:https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-3.1

转载地址:http://mmgbi.baihongyu.com/

你可能感兴趣的文章
慢慢欣赏linux 网络协议栈一 全景图
查看>>
慢慢欣赏linux 网络协议栈二 net_device以及初始化注册
查看>>
慢慢欣赏linux 网络协议栈三 监听链路状态
查看>>
慢慢欣赏linux 网络协议栈四 sk_buff以及数据收发
查看>>
慢慢欣赏linux 内核定位手段printk
查看>>
慢慢欣赏linux 网络协议栈七 虚拟网卡
查看>>
linux设备驱动模型代码分析
查看>>
uboot入门学习二 位置无关代码以及地址
查看>>
慢慢欣赏linux 块设备驱动基础
查看>>
慢慢欣赏linux文件缓冲区 mmap分析
查看>>
慢慢欣赏linux 页面回收
查看>>
微视linux waitX的意义
查看>>
微视linux 挂接中断action的前奏 设置中断处理函数
查看>>
RCU锁学习
查看>>
ppc解析保留内存
查看>>
微视linux uboot保留内存的传递
查看>>
微视linux scsi驱动错误中断处理
查看>>
linux动态库学习
查看>>
微视linux 释放文件节点流程
查看>>
new的过程
查看>>