ASP .NET Core 健康检查
简介
健康检查,其实这个名称已经很明确了,它是检查你的应用程序是否健康运行的一种方式。随着当前各类项目越来越多的应用程序正在转向微服务式架构,健康检查就变得尤为关键。虽然微服务体系结构具有许多好处,但其中一个缺点就是为了确保所有这些服务都正常运行的操作开销更高。你不在是监视一个庞大的整体项目的健康状况,而是需要监控许多不同服务的状态,甚至这些服务通常只负责一件事情。健康检查(Heatlh Checks)通常与一些服务发现工具结合使用,如Consul ,来监控您的微服务器,来观测您的服务是否健康运行。
健康检查有很多种不同的方法,但最常见的方法是将HTTP端点暴露给专门用于健康检查的应用程序。一般来说,如果一切情况都很好,你的服务将返回200的状态码,然而任何非200的代码则意味着出现问题。例如,如果发生错误,你可能会返回500以及一些出错的JSON信息。
举例一些常见的健康检查内容:
- 检查我的服务可以连接到数据库吗?
- 检查我的服务可以查询第三方API吗?
- 可能做一些只读操作
- 我的服务可以访问文件系统吗(IO是否正常)?
- 检查我的服务占用的内存或CPU是否高于某个阈值?
健康检查有三个登记
- Healthy 健康
- Unhealthy 不良
- Degraded 降级
ASP.NET Core实现
Neget安装以下包
AspNetCore.HealthChecks.UI
AspNetCore.HealthChecks.UI.Client
AspNetCore.HealthChecks.UI.InMemory.Storage
Microsoft.Extensions.Diagnostics.HealthChecks
添加检查测试案例
services.AddHealthChecks()
.AddCheck("Foo", () =>
HealthCheckResult.Healthy("健康"), tags: new[] { "foo_tag" })
.AddCheck("Bar", () =>
HealthCheckResult.Unhealthy("不良"), tags: new[] { "bar_tag" })
.AddCheck("Baz", () =>
HealthCheckResult.Degraded("降级"), tags: new[] { "baz_tag" });
添加检查
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace WebApplication6.HealthChecks
{
public class DatabaseHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken =
default)
{
try
{
return Task.FromResult(HealthCheckResult.Healthy($"API is running."));
}
catch (Exception ex)
{
return Task.FromResult(HealthCheckResult.Unhealthy("DB is not Healthy", ex));
}
}
}
}
appsettings.json
添加HealthChecksUI
配置
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"HealthChecks-UI": {
"HealthChecks": [
{
"Name": "Local",
"Uri": "http://localhost:5000/health"
}
//{
// "Name": "",
// "Uri": ""
//}
],
"Webhooks": [
{
"Name": "",
"Uri": "",
"Payload": "",
"RestoredPayload": ""
}
],
"EvaluationTimeOnSeconds": 10,
"MinimumSecondsBetweenFailureNotifications": 60
}
}
Startup
添加HealthCheck
服务和HealthCheckUI
界面
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using WebApplication6.HealthChecks;
namespace WebApplication6
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddHealthChecks()
.AddCheck("Foo", () =>
HealthCheckResult.Healthy("健康"), tags: new[] { "foo_tag" })
.AddCheck("Bar", () =>
HealthCheckResult.Unhealthy("不良"), tags: new[] { "bar_tag" })
.AddCheck("Baz", () =>
HealthCheckResult.Degraded("降级"), tags: new[] { "baz_tag" });
//添加DatabaseHealthCheck,30S轮询健康检查一次
services.AddHealthChecks().AddCheck<DatabaseHealthCheck>(nameof(DatabaseHealthCheck));
//需要安装Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore包
//.AddDbContextCheck<Microsoft.EntityFrameworkCore.DbContext>("DbContext");
//添加UI 内存存储
services.AddHealthChecksUI().AddInMemoryStorage();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseHealthChecksUI();
HealthCheckOptions healthCheckOptions = new HealthCheckOptions
{
AllowCachingResponses = false,
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
ResultStatusCodes =
{
[HealthStatus.Healthy] = StatusCodes.Status200OK,
[HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable,
[HealthStatus.Degraded] = StatusCodes.Status500InternalServerError,
[HealthStatus.Degraded] = StatusCodes.Status419AuthenticationTimeout
}
};
app.UseHealthChecks("/health", healthCheckOptions);
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
访问http://localhost:5000/health
查看健康检查
访问http://localhost:5000/healthchecks-ui
查看健康检查UI界面
主动健康检查
主动健康检查进行有两种方式
- 访问
http://localhost:5000/health
健康检查地址 - Controller访问以下Api
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System.Net;
namespace WebApplication2.Controllers
{
[ApiController]
[Route("[controller]")]
public class HealthController : ControllerBase
{
private readonly HealthCheckService _healthCheckService;
public HealthController(HealthCheckService healthCheckService) => _healthCheckService = healthCheckService;
[HttpGet]
public async Task<IActionResult> Get()
{
var report = await _healthCheckService.CheckHealthAsync();
return report.Status == HealthStatus.Healthy ? Ok(report) : StatusCode((int)HttpStatusCode.ServiceUnavailable, report);
}
}
}
程序自身健康检查
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace WebApplication6.HealthChecks
{
public class DelayStartupHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken =
default)
{
if (DelayStartup.StartupReady)
{
return Task.FromResult(HealthCheckResult.Healthy());
}
return Task.FromResult(HealthCheckResult.Unhealthy());
}
}
public class DelayStartup
{
public static bool StartupReady { get; private set; } = false;
private static long DelaySeconds = 60;
private static Semaphore semaphore = new Semaphore(0, 1);
static DelayStartup()
{
try
{
//IConfiguration configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
//DelaySeconds = int.Parse(configuration["App:DelayStartup"]);
DelaySeconds = 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
DelaySeconds = 0;
}
if (DelaySeconds > 0)
{
Startup();
}
else
{
StartupReady = true;
}
}
private static void Startup()
{
DateTime start = DateTime.Now;
Task.Factory.StartNew(() =>
{
while (true)
{
if (DateTime.Now.Subtract(start).TotalSeconds >= DelaySeconds)
{
StartupReady = true;
Console.WriteLine("DelayStartup StartupReady");
break;
}
Console.WriteLine("DelayStartup Checking");
semaphore.WaitOne(2000);
}
});
}
}
}
Neget包
#主包
Install-Package Microsoft.Extensions.Diagnostics.HealthChecks
#UI
Install-Package AspNetCore.HealthChecks.UI
Install-Package AspNetCore.HealthChecks.UI.Client
#UI存储
Install-Package AspNetCore.HealthChecks.UI.InMemory.Storage
Install-Package AspNetCore.HealthChecks.UI.SqlServer.Storage
Install-Package AspNetCore.HealthChecks.UI.SQLite.Storage
Install-Package AspNetCore.HealthChecks.UI.PostgreSQL.Storage
Install-Package AspNetCore.HealthChecks.UI.MySql.Storage
#HealthCheckReport 发送
Install-Package AspNetcore.HealthChecks.Publisher.ApplicationInsights
Install-Package AspNetcore.HealthChecks.Publisher.CloudWatch
Install-Package AspNetcore.HealthChecks.Publisher.Datadog
Install-Package AspNetcore.HealthChecks.Publisher.Prometheus
Install-Package AspNetcore.HealthChecks.Publisher.Seq
#健康检查
Install-Package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
Install-Package AspNetCore.HealthChecks.ApplicationStatus
Install-Package AspNetCore.HealthChecks.ArangoDb
Install-Package AspNetCore.HealthChecks.Aws.S3
Install-Package AspNetCore.HealthChecks.Aws.SecretsManager
Install-Package AspNetCore.HealthChecks.Aws.Sns
Install-Package AspNetCore.HealthChecks.Aws.Sqs
Install-Package AspNetCore.HealthChecks.Aws.SystemsManager
Install-Package AspNetCore.HealthChecks.Azure.IoTHub
Install-Package AspNetCore.HealthChecks.AzureDigitalTwin
Install-Package AspNetCore.HealthChecks.AzureKeyVault
Install-Package AspNetCore.HealthChecks.AzureServiceBus
Install-Package AspNetCore.HealthChecks.AzureStorage
Install-Package AspNetCore.HealthChecks.Consul
Install-Package AspNetCore.HealthChecks.CosmosDb
Install-Package AspNetCore.HealthChecks.DocumentDb
Install-Package AspNetCore.HealthChecks.DynamoDB
Install-Package AspNetCore.HealthChecks.Elasticsearch
Install-Package AspNetCore.HealthChecks.EventStore
Install-Package AspNetCore.HealthChecks.EventStore.gRPC
Install-Package AspNetCore.HealthChecks.Gcp.CloudFirestore
Install-Package AspNetCore.HealthChecks.Gremlin
Install-Package AspNetCore.HealthChecks.Hangfire
Install-Package AspNetCore.HealthChecks.IbmMQ
Install-Package AspNetCore.HealthChecks.Kafka
Install-Package AspNetCore.HealthChecks.Kubernetes
Install-Package AspNetCore.HealthChecks.MongoDb
Install-Package AspNetCore.HealthChecks.MySql
Install-Package AspNetCore.HealthChecks.Nats
Install-Package AspNetCore.HealthChecks.Network
Install-Package AspNetCore.HealthChecks.Npgsql
Install-Package AspNetCore.HealthChecks.OpenIdConnectServer
Install-Package AspNetCore.HealthChecks.Oracle
Install-Package AspNetCore.HealthChecks.RabbitMQ
Install-Package AspNetCore.HealthChecks.RavenDB
Install-Package AspNetCore.HealthChecks.Redis
Install-Package AspNetCore.HealthChecks.SendGrid
Install-Package AspNetCore.HealthChecks.SignalR
Install-Package AspNetCore.HealthChecks.Solr
Install-Package AspNetCore.HealthChecks.SqLite
Install-Package AspNetCore.HealthChecks.SqlServer
Install-Package AspNetCore.HealthChecks.System
Install-Package AspNetCore.HealthChecks.Uris