【愚公系列】2022年12月 .NET CORE工具案例-分布式服务的健康检查系统

举报
愚公搬代码 发表于 2022/12/30 23:16:09 2022/12/30
【摘要】 前言 1.健康检查系统来源背景互联网产品对用户体验提出了很高的要求,但常常由于技术侧原因,发生服务响应慢或者服务不可用等一系列影响用户体验的问题,导致业务中断,影响收入。影响服务不可用和响应慢的因素很多,可能是服务硬件损坏、光纤被挖断,可能是请求量过大导致数据库CPU负载、磁盘IO过高等等。 2.健康检查系统的作用要保证系统高可用,主要就是消除单节点故障,消除单节点故障是系统高可用的常用手...

前言

1.健康检查系统来源背景

互联网产品对用户体验提出了很高的要求,但常常由于技术侧原因,发生服务响应慢或者服务不可用等一系列影响用户体验的问题,导致业务中断,影响收入。影响服务不可用和响应慢的因素很多,可能是服务硬件损坏、光纤被挖断,可能是请求量过大导致数据库CPU负载、磁盘IO过高等等。

2.健康检查系统的作用

要保证系统高可用,主要就是消除单节点故障,消除单节点故障是系统高可用的常用手段。消除单节点有一个很重要的前提是发现问题节点,把问题节点踢除或者把流量切换到其他正常节点。

如何“发现问题节点”,就是系统健康检查需要做的事情。

3.如何涉及健康检查系统

谈论如何做健康检查前,首先要弄明白的是要检查的对象究竟是谁。对象可以网络连接,可以是一个小小的功能组件,可以是一个进程,可以是服务集群,也可以是机房单元。在开发AspNet Core应用的时候,我们经常会为该应用公布一个特殊的检测接口出来。该接口的目的很简单,告诉外界程序当前程序现在是可以访问或者不能访问的,便于外界做出相应的操作,比如监控报警,页面通知用户稍作等待等。

一、分布式服务的健康检查系统

1.官方包的使用

1、添加健康检查类和响应输出方法

/// <summary>
/// mysql健康检查
/// </summary>
public class MySQLHealthCheck : IHealthCheck
{
    public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        try
        {
            return await Task.FromResult(HealthCheckResult.Healthy()).ConfigureAwait(false);
        }
        catch
        {
            return await Task.FromResult(HealthCheckResult.Unhealthy("From Sql Serve")).ConfigureAwait(false);
        }
    }
}

/// <summary>
/// redis健康检查
/// </summary>
public class RedisHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        return Task.FromResult(HealthCheckResult.Healthy());
    }
}
public static class Response
{
    /// <summary>
    /// 返回指定格式
    /// </summary>
    /// <param name="context"></param>
    /// <param name="result"></param>
    /// <returns></returns>
    private static Task WriteResponse(HttpContext context, HealthReport result)
    {
        context.Response.ContentType = "application/json";

        var json = new JObject(
            new JProperty("status", result.Status.ToString()),
            new JProperty("results", new JObject(result.Entries.Select(pair => new JProperty(pair.Key,
                new JObject(new JProperty("status", pair.Value.Status.ToString()),
                    new JProperty("description", pair.Value.Description),
                    new JProperty("data", new JObject(pair.Value.Data.Select(
                        p => new JProperty(p.Key, p.Value))))))))));

        return context.Response.WriteAsync(json.ToString());
    }
}

在这里插入图片描述

2、注入服务

//添加健康检查服务
builder.Services.AddHealthChecks()
    .AddCheck<MySQLHealthCheck>("mysql_check")
    .AddCheck<RedisHealthCheck>("redis_check");
//健康检查服务接口地址
app.MapHealthChecks("/mysqlhealth", new HealthCheckOptions()
{//mysql
    Predicate = s => s.Name.Equals("mysql_check"),
    ResponseWriter = (HttpContext context, HealthReport result) =>
        {
            context.Response.ContentType = "application/json";

            var json = new JObject(
                new JProperty("status", result.Status.ToString()),
                new JProperty("results", new JObject(result.Entries.Select(pair => new JProperty(pair.Key,
                    new JObject(new JProperty("status", pair.Value.Status.ToString()),
                        new JProperty("description", pair.Value.Description),
                        new JProperty("data", new JObject(pair.Value.Data.Select(
                            p => new JProperty(p.Key, p.Value))))))))));

            return context.Response.WriteAsync(json.ToString());
        }
});

app.MapHealthChecks("/redishealth", new HealthCheckOptions() //redis
{
    Predicate = s => s.Name.Equals("redis_check"),
    ResponseWriter = (HttpContext context, HealthReport result) =>
    {
        context.Response.ContentType = "application/json";

        var json = new JObject(
            new JProperty("status", result.Status.ToString()),
            new JProperty("results", new JObject(result.Entries.Select(pair => new JProperty(pair.Key,
                new JObject(new JProperty("status", pair.Value.Status.ToString()),
                    new JProperty("description", pair.Value.Description),
                    new JProperty("data", new JObject(pair.Value.Data.Select(
                        p => new JProperty(p.Key, p.Value))))))))));

        return context.Response.WriteAsync(json.ToString());
    }
});

在这里插入图片描述

通过访问地址:http://ip:端口/mysqlhealth 查看mysql连接状态
通过访问地址:http://ip:端口/redishealth  查看redis连接状态

在这里插入图片描述

2.第三方包的使用

2.1 第三方包

GitHub:https://github.com/xabaril/AspNetCore.Diagnostics.HealthChecks
在这里插入图片描述

支持的服务健康检查的包有

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

2.2 安装包

AspNetCore.HealthChecks.UI
AspNetCore.HealthChecks.UI.Client
AspNetCore.HealthChecks.UI.InMemory.Storage
AspNetCore.HealthChecks.MySql
AspNetCore.HealthChecks.Redis

在这里插入图片描述

2.3 设置启动

1、自写类监控检查

//添加健康检查服务
builder.Services.AddHealthChecks()
    .AddCheck<MySqlHealthCheck>("mysql_check")
    .AddCheck<RedisHealthCheck>("redis_check");
builder.Services.AddHealthChecksUI().AddInMemoryStorage();

//健康检查服务接口地址
app.MapHealthChecks("/mysqlhealth", new HealthCheckOptions()
{
    Predicate = s => s.Name.Equals("mysql_check"),
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

app.MapHealthChecks("/redishealth", new HealthCheckOptions()
{
    Predicate = s => s.Name.Equals("redis_check"),
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

app.MapHealthChecksUI();

在这里插入图片描述
启动程序访问:/healthchecks-ui 地址
在这里插入图片描述
2、相关包监控检查

//添加健康检查服务
builder.Services.AddHealthChecks()
    .AddTypeActivatedCheck<MySqlHealthCheck>("mysql_check", args: new[] { "server=120.79.63.89;userid=root;pwd=123456;port=3308;database=DB_SY_ERP;sslmode=none" })
    .AddTypeActivatedCheck<RedisHealthCheck>("redis_check", args: new[] { "localhost:6379,defaultDatabase=1" });

builder.Services.AddHealthChecksUI(setup =>
{
    //可配置
    setup.SetEvaluationTimeInSeconds(5); // UI 配置轮询间隔(以秒为单位)
    setup.SetApiMaxActiveRequests(1); // 运行状况检查 UI 后端 API 的最大活动请求数
    setup.MaximumHistoryEntriesPerEndpoint(50);//提供的最大历史记录条目数
    //setup.AddHealthCheckEndpoint("endpoint1", "http://localhost:8001/healthz");
    //setup.AddHealthCheckEndpoint("endpoint2", "http://remoteendpoint:9000/healthz");
    //setup.AddWebhookNotification("webhook1", uri: "http://httpbin.org/status/200?code=ax3rt56s", payload: "{...}");

}).AddInMemoryStorage();

//健康检查服务接口地址
app.MapHealthChecks("/mysqlhealth", new HealthCheckOptions()
{
    Predicate = s => s.Name.Equals("mysql_check"),
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

app.MapHealthChecks("/redishealth", new HealthCheckOptions()
{
    Predicate = s => s.Name.Equals("redis_check"),
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.MapHealthChecksUI();

在这里插入图片描述
启动程序访问:/healthchecks-ui 地址
在这里插入图片描述
启动redis看下
在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。