只有累積,沒有奇蹟

2023年2月22日 星期三

[NETCore] 如何設定 ASP.NET Core 健康檢查(Health Check)功能 - Health Check UI

前言
在前一篇針對 ASP.NET Core 2.2 新特性 Health Check功能做基本的介紹,接著要分享的是在 BeatPulse 中實用的功能 Health Check UI,提供 UI 介面顯示及儲存 Health Check 檢查的結果內容,如果有多台時也可以在設定檔加上指定 URL 達到同時監控多台的效果,此篇就針對 Health Check UI 做介紹若有問題或是錯誤的地方歡迎網路的高手大大給予指導

Health Check UI
要使用 Health Check UI 起手式是要安裝其套件  AspNetCore.HealthChecks.UI ,指令如下
install-package AspNetCore.HealthChecks.UI  
安裝完 nuget package 之後,在 Startup.cs 要註冊 service 與 middleware,定義 healthCheck 的路徑為 /hc,UI 顯示的路徑為 /hc-ui
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecksUI();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseHealthChecks("/hc", new HealthCheckOptions
        {
            Predicate = _ => true,
            ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
        });

        app.UseHealthChecksUI(options =>
        {
            options.UIPath = "/hc-ui";
        });        
    }
}  
下一步是 appsettings.json 加上 healthCheckUI 設定資訊,設定包含要檢查的內容網址、多久執行檢查的動作與發生意外時的處理機制,這裡設定每 10 秒進行一次檢查,檢查的內容來源為 /hc
"HealthChecks-UI": {
    "HealthChecks": [
      {
        "Name": "Health Check Demo",
        "Uri": "http://localhost:5000/hc"
      }
    ],
    "EvaluationTimeOnSeconds": 10,
    "MinimumSecondsBetweenFailureNotifications": 60
  }
檢查內容這裡沿用上一篇介紹 healthCheck 的內容項目,檢查 mssql、Redis、Memory 與第三方 url 檢康狀況,這裡就不在多加說明,想了解細節可以參考上一篇文章內容說明
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
    services.AddHealthChecksUI();

    services.AddHealthChecks()
        .AddMemoryHealthCheck("Memory Health Check")
        .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"], name: "SQL Server HealthCheck")
        .AddRedis(Configuration["ConnectionStrings:RedisConn"], name: "Redis HealthCheck")
        .AddUrlGroup(new Uri("https://marcus116.blogspot.com"), "ThirdParty API HealthCheck",HealthStatus.Degraded);
    //省略
}
以上設定完畢後,執行專案並在瀏覽器輸入 /hc-ui,就可以看到將檢查的字串內容變為圖像顯示

Docker Image
作者也有提供 Docker health check image 給需要的人使用,可以透過 docker pull 取得 health check image 並使用 docker run 來執行
PS C:\> docker pull xabarilcoding/healthchecksui
Using default tag: latest
latest: Pulling from xabarilcoding/healthchecksui
27833a3ba0a5: Pull complete
25dbf7dc93e5: Pull complete
0ed9cb15d3b8: Pull complete
874ea13b7488: Pull complete
73d82f2e96ee: Pull complete
f856979cdc5c: Pull complete
Digest: sha256:fe18f7655f05872cd8b2644ce7d4603b1d03ae4e0b24fa59f4d960cdc7bde6c4
Status: Downloaded newer image for xabarilcoding/healthchecksui:latest
PS C:\> docker run --name healthcheck-ui -p 5000:80 -d xabarilcoding/healthchecksui:latest
詳細可以參考 HealthChecks UI Docker Image

感想
使用 health Check UI 幫助我們可以更快的了解需要檢查應用程式的健康狀態資訊,如果您的應用程式有不止一台,可以在 health Check Ui 設定檔節點新增多筆檢查來源與名稱來自訂不同的檢查行為,舉例來說 MSDN 有列出如果 Health Check 顯示多筆,希望這篇介紹可以有幫助到有需要的朋友,謝謝

參考
Health checks in ASP.NET Core
ASP.NET Core MVC - 2.2 Health Checks


2023年2月6日 星期一

[NETCore] 如何設定 ASP.NET Core 健康檢查(Health Check)功能

前言
過去當應用程式開發完成之後,另外一項重要的事情就是建立上線後的監控機制,尤其是重要性高的服務更是不可或缺的事情,有遇過公司是在站台底下放置一個檔案內容文字是OK,在透過工具固定時間去確認網站底下這檔案是否有正常回傳,就可代表網站是否存活者,各種不同的實作方式都可以達到此目的; ASP.NET Core 2.2 開始提供 Health Check 中介層 (Middleware),透過 HTTP 方式可以即時取得應用程式的健康狀況,在使用與設定上容易上手,此篇介紹在 ASP.NET Core 中如何使用及設定 Health Check 的方式,即時的取得應用程式健康狀況若有問題或是錯誤的地方歡迎網路的高手大大給予指導

基本使用
Health Check 為 ASP.NET Core 2.2 內建,因此使用前不需要透過 nuget 下載任何 package 套件,只需要簡單的註冊服務就可以使用,首先在  Sartup.cs  中的 ConfigureServices 方法中加上 AddHealthChecks 註冊 Health Checks 服務,接著在 configure 中新增 UseHealthChecks middleware 並指定位置,即可完成基本的 Health Chcek 健康檢查的應用,代碼如下
public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseHealthChecks("/health");

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Navigate to /health to see the health status.");
    });
} 
執行應用程式,透過瀏覽器開啟 /health 就可以看到回傳的結果

HealthCheckOptions
上面介紹了最基本的使用方式,實務上常常會需要得到更多資訊,有時候可能會需要自定義 Health Check 回傳的 HTTP Status 狀態,或是輸出不同的格式情境時,就可以使用  HealthCheclOptions  來自訂不同的檢查行為,以下範例是自訂檢查輸出為 Json,並輸出檢查細節的所有內容資訊
app.UseHealthChecks("/health", new HealthCheckOptions
{
    ResponseWriter = async (context, report) =>
    {
        var json = JsonConvert.SerializeObject(report);
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(json);
    }
});
回傳結果為目前應用程式狀態是正常 (Status=2=Health),以及 Health Check 所花費的時間
{
    "Entries": {},
    "Status": 2,
    "TotalDuration": "00:00:00.0000048"
}
當然如果只想要內容跟結果,可以調整 HealthCheckOptions 內容輸出指定需要的資訊,舉例來說我只想看 Status 跟 error 內容,代碼如下
app.UseHealthChecks("/health",
    new HealthCheckOptions
    {
        ResponseWriter = async (context, report) =>
        {
            var result = JsonConvert.SerializeObject(
                new
                {
                    status = report.Status.ToString(),
                    errors = report.Entries.Select(e => new { key = e.Key, value = Enum.GetName(typeof(HealthStatus), e.Value.Status) })
                });
            context.Response.ContentType = MediaTypeNames.Application.Json;
            await context.Response.WriteAsync(result);
        }
    });
回傳結果如下
{
    "Status": 2,
    "error": []
}

檢查依賴項目健康狀態
應用程式在開發中會使用到資料庫或是不同服務,BeatPulse 提供多個檢查項目的 API,透過這些 API 可以檢查依賴內容的健康狀況,舉例來說可以檢查 SQL、Redis、Network、Kafka、Aws.S3 等不同依賴於應用程式所使用的服務,如果要使用時後僅需要下載對應 package 和使用擴充方法就健康資訊。
舉例來說我的 ASP.NET Core API 有資料庫是使用 MS SQL,Cache 是使用 Redis,另外還有使用到第三方 API,以上可以在 Health Check 中設定,首先須先下載用到的 package
Install-Package AspNetCore.HealthChecks.SqlServer
Install-Package AspNetCore.HealthChecks.Redis
Install-Package AspNetCore.HealthChecks.Uris
接著在ConfigureServices 方法中加上 AddSqlServer、AddRedis、AddUrlGroup 等擴充方法,並指定其連線字串及網址內容 
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddHealthChecks()
        .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"], name: "SQL Server HealthCheck")
        .AddRedis(Configuration["ConnectionStrings:RedisConn"], name: "Redis HealthCheck")
        .AddUrlGroup(new Uri("https://marcus116.blogspot.com"), "ThirdParty API HealthCheck", HealthStatus.Degraded);
}
執行應用程式並開啟 health 頁面,可以看到檢查 MSSQL、Redis 以及外部服務 Domain 的結果
在每個 Health Check 方法也支援參數指定其標籤、名稱、失敗時的狀態等資訊,以下為 SQL Server 檢查,如果有需要的話也可以建立多個 SQL Server 健康檢查
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddHealthChecks()
                .AddSqlServer(
                    connectionString: Configuration["ConnectionStrings:DefaultConnection"],
                    healthQuery: "select 1",
                    name: "MSSQL Check",
                    failureStatus: HealthStatus.Degraded,
                    tags: new string[] {"database", "sqlServer"});
}
更多細節及說明可以參考 GitHub 上的官網內容 : 傳送門 

自訂健康檢查
假設在 AspNetCore.Diagnostics.HealthChecks 都不符合您的需求,可以透過實作  IHealthCheck  介面來自己定義需要健檢的項目內容,舉例來說可以檢查應用程式記憶體 (Memory) 的使用量,如果使用超過設定值時就會報告狀態為不健康有可能需要降級的動作,下列代碼為參考 MSDN 定義的 MemoryHealthCheck 方法與 MemoryCheckOptions 類別,定義 Memory 上限水位為 1G
public class MemoryHealthCheck : IHealthCheck
{
    private readonly IOptionsMonitor<MemoryCheckOptions> _options;

    public MemoryHealthCheck(IOptionsMonitor<MemoryCheckOptions> options)
    {
        _options = options;
    }

    public string Name => "memory_check";

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var options = _options.Get(context.Registration.Name);

        // Include GC information in the reported diagnostics.
        var allocated = GC.GetTotalMemory(forceFullCollection: false);
        var data = new Dictionary<string, object>()
        {
            { "AllocatedBytes", allocated },
            { "Gen0Collections", GC.CollectionCount(0) },
            { "Gen1Collections", GC.CollectionCount(1) },
            { "Gen2Collections", GC.CollectionCount(2) },
        };

        var status = (allocated < options.Threshold) ?
            HealthStatus.Healthy : HealthStatus.Unhealthy;

        return Task.FromResult(new HealthCheckResult(
            status,
            description: "Reports degraded status if allocated bytes " +
                         $">= {options.Threshold} bytes.",
            exception: null,
            data: data));
    }
}

public class MemoryCheckOptions
{
    // Failure threshold (in bytes)
    public long Threshold { get; set; } = 1024L * 1024L * 1024L;
}
接著可以透過兩種方式加入檢查

AddMemoryHealthCheck 擴充方法
要來寫  AddMemoryHealthCheck  擴充方法,在 ConfigureServices 才可以用到
public static class GCInfoHealthCheckBuilderExtensions
{
    public static IHealthChecksBuilder AddMemoryHealthCheck(
        this IHealthChecksBuilder builder,
        string name,
        HealthStatus? failureStatus = null,
        IEnumerable<string> tags = null,
        long? thresholdInBytes = null)
    {
        // Register a check of type GCInfo.
        builder.AddCheck<Startup.MemoryHealthCheck>(
            name, failureStatus ?? HealthStatus.Degraded, tags);

        // Configure named options to pass the threshold into the check.
        if (thresholdInBytes.HasValue)
        {
            builder.Services.Configure<Startup.MemoryCheckOptions>(name, options =>
            {
                options.Threshold = thresholdInBytes.Value;
            });
        }

        return builder;
    }
}
下一步就是與之前說明的相同,到 ConfigureServices 加上 AddMemoryHealthCheck 方法,另外還想知道自訂檢查中的 GC 記憶體用量狀況 (GenCollections 0、1、2),因此 Config 內容也調整為輸出全部資訊
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddHealthChecks()
        .AddMemoryHealthCheck("Memory Health Check");
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseHealthChecks("/health",
        new HealthCheckOptions
        {
            ResponseWriter = async (context, report) =>
            {
                var result = JsonConvert.SerializeObject(report);
                context.Response.ContentType = MediaTypeNames.Application.Json;
                await context.Response.WriteAsync(result);
            }
        });

    // 省略 
}
重新執行應用程式,成功輸出其內容資訊

AddCheck<T>
使用  AddCheck  注入的方式加入檢查,如下  
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddHealthChecks()
        .AddCheck<MemoryHealthCheck>("Memory Health Check");

        services.AddSingleton<MemoryHealthCheck>();
    // 省略
}
結果與使用 AddMemoryHealthCheck 相同,這裡就不在重複貼。

感想
介紹了很多 ASP.NET Core 新功能 Health Check 的基本使用,相信對於在 ASP.NET Core 中使用 health check 了解更多,以上算是簡單的使用情境說明,當應用程式不只一台或是要健檢的項目變多的時候,確認 health check 回傳的 status 狀況上就會變得不單純,因此下一篇會介紹 Health Check UI 的設定及如何使用 Publisher 方式推到某一台方便進行監控及管理,希望這篇介紹可以有幫助到有需要的朋友,謝謝

參考
Health checks in ASP.NET Core
AspNetCore.Diagnostics.HealthChecks
ASP.NET Core MVC - 2.2 Health Checks
AspNetCore 2.2 新特性---HealthCheck
How to set up ASP.NET Core 2.2 Health Checks 
Using the Microsoft.AspNetCore.HealthChecks Package
Health Checks in ASP.NET Core

Copyright © m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com