ASP.NET Core-使用HealthCheck對程序健康檢查

正文

在開發AspNet Core應用的時候,我們經常會爲該應用公佈一個特殊的檢測接口出來。該接口的目的很簡單,告訴外界程序當前程序現在是可以訪問或者不能訪問的,便於外界做出相應的操作,比如監控報警,頁面通知用戶稍作等待等。

AspNet Core 2.2 之前,如果我們要實現一個這樣的檢測接口,需要建立一個單獨的controller,比如HealthController。然後爲其實現一個簡單的檢測方法:

[Route("working")]
public ActionResult Working()
{
    using (var connection = new SqlConnection(_connectionString))
    {
        try
        {
            connection.Open();
        }
        catch (SqlException)
        {
            return new HttpStatusCodeResult(503, "Generic error");
        }
    }
    return new EmptyResult();
}

該接口目的是檢測應用與數據庫的連接能否成功。如果成功連接,則返回狀態碼爲200的空內容,如果失敗則返回503。 外界程序可以通過定時訪問 “\working” 路徑。

運行狀況檢查

但是在Aspnet Core 2.2 之後,我們有了新的解決方式。只需要簡單的操作就可以進行程序運行狀況的檢查。

我們只需要在Startup.cs中添加兩句話就OK了:

public void ConfigureServices(IServiceCollection services)
{
    //使用該擴展方法
    services.AddHealthChecks();
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        //使用該擴展方法
        endpoints.MapHealthChecks("/health");
    });
}

默認情況是不需要在額外的引入其它nuget包的,因爲AspNet Core自帶了這些功能。

此時我們可以訪問 "/health" 路徑,如果程序正常,則返回Http狀態碼爲200,顯示內容爲"Healthy"的結果。如果程序不正常,則返回Http狀態碼爲503,顯示內容爲"UnHealthy"的結果。

這就是運行狀況檢查的初步使用。

目的性的檢查

最初我們只是簡單的引入了 AddHealthChecks 。 但是它並沒有任何特定的邏輯在裏面。而現實場景我們是需要對各種指標進行檢查的,所以我們需要實現自定義的檢查功能。

比如咱們現在要實現一個對Sql Server 連接情況的檢查。我們只需要實現 IHealthCheck 接口,實現CheckHealthAsync 方法就可以了:

public class SqlServerHealthCheck : IHealthCheck
{
    SqlConnection _connection;

    public string Name => "sql";

    public SqlServerHealthCheck(SqlConnection connection)
    {
        _connection = connection;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        try
        {
            _connection.Open();
        }
        catch (SqlException)
        {
            return Task.FromResult(HealthCheckResult.Unhealthy("From Sql Serve"));
        }

        return Task.FromResult(HealthCheckResult.Healthy());
    }
}

然後在Startup.csAddHealthChecks進行擴展:

services.AddHealthChecks()
        .AddCheck<SqlServerHealthCheck>("sql_check");

此時如果咱們再次訪問"/health" 路徑,就會發現應用會執行SqlServerHealthCheck裏面的檢查邏輯。

但是實際情況,咱們往往都會有許許多多的檢查項,比如增加一個叫做MemoryHealthCheck的檢查項:

public class MemoryHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        //doing some memory check things.
        return Task.FromResult(HealthCheckResult.Healthy());
    }
}

// startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
            .AddCheck<SqlServerHealthCheck>("sql_check")
            .AddCheck<MemoryHealthCheck>("memory_check");  // add this line
}

或許還有許許多多的檢查項:FileSizeHealthCheck,RedisHealthCheck等等。當我們將它們都添加上之後,則只有當所有的檢查器都返回爲Healthy的時候,纔會認爲是健康。

但是某些情況我們又只想進行單項檢查怎麼辦呢? 我們可以在 endpoints 的配置中新增另外的路由映射規則:

// startup.cs
 app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = s => s.Name.Equals("sql_check"),
        ResponseWriter = WriteResponse
    });

    endpoints.MapHealthChecks("/healthy", new HealthCheckOptions()
    {
        Predicate = s => s.Name.Equals("memory_check"),
        ResponseWriter = WriteResponse
    });
});

//指定返回格式
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());
}

我們在原有的基礎上增加了HealthCheckOptions的參數,該參數指定了關於狀態檢測的匹配規則,返回狀態碼,返回格式等信息。

上面的代碼我們指定了兩個路由。當訪問"health"路徑的時候,則是對sql連接的檢查(根據檢查器名來匹配:Name.Equals("sql_check")),而訪問"healthy"路徑的時候,是對內存的檢查。 最後還爲他們指定了需要返回的內容(WriteResponse)。

自定義返回內容對咱們定位錯誤和記錄日誌十分有用。

第三方支持

雖然官方爲我們提供的運行檢查庫已經足夠輕量和簡單。但是爲了避免重複造輪子,我們可以使用AspNetCore.Diagnostics.HealthChecks包,該項目包含了許多情況的檢查,比如 Sql Server、MySql、Elasticsearch、Redis、Kafka等等。

並且還爲我們提供一個UI界面,可供查看。只需要在原有的基礎上引入對應的代碼就行了:

 public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
            .AddCheck<SqlServerHealthCheck>("sql_check")
            .AddCheck<MemoryHealthCheck>("memory_check");

    // add this line
    services.AddHealthChecksUI();
}

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = s => s.Name.Equals("sql_check"),
        ResponseWriter = WriteResponse
    });
    //add this line
    endpoints.MapHealthChecksUI();
});

當我們訪問"/healthchecks-ui"路徑時,就可以看到這樣的UI:

默認是沒有任何的檢測配置項的,如果咱們需要可視化運行狀態,需要添加配置:

"HealthChecksUI": {
"HealthChecks": [
{
"Name": "db_check",
"Uri": "http://localhost:5000/db_health"
}
],
"EvaluationTimeinSeconds": 10,
"MinimumSecondsBetweenFailureNotifications": 60
}

再次查看UI界面

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章