1. 程式人生 > >【5min+】保持程式健康的祕訣!AspNetCore的HealthCheck

【5min+】保持程式健康的祕訣!AspNetCore的HealthCheck

系列介紹

【五分鐘的dotnet】是一個利用您的碎片化時間來學習和豐富.net知識的博文系列。它所包含了.net體系中可能會涉及到的方方面面,比如C#的小細節,AspnetCore,微服務中的.net知識等等。
5min+不是超過5分鐘的意思,"+"是知識的增加。so,它是讓您花費5分鐘以下的時間來提升您的知識儲備量。

正文

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

在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” 路徑,根據返回的對應Code來做出相應的反應。

執行狀況檢查

但是在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
}

或許還有許許多多的檢查項:FileSizeHealthCheckRedisHealthCheck等等。當我們將它們都新增上之後,則只有當所有的檢查器都返回為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)。

接下來我們再次進行請求"health"路徑,就會得到下面的結果:

自定義返回內容對咱們定位錯誤和記錄日誌十分有用。(就像看病的例子,病人更清晰的描述病情,醫生就能夠更容易定位病因。)。

第三方支援

雖然官方為我們提供的執行檢查庫已經足夠輕量和簡單。但是為了避免重複造輪子,我們可以使用AspNetCore.Diagnostics.HealthChecks包,該專案包含了許多情況的檢查,比如 Sql ServerMySqlElasticsearchRedisKafka等等。

並且還為我們提供一個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:

預設是沒有任何的檢測配置項的,如果咱們需要視覺化執行狀態,需要在AddHealthChecksUI中進行配置:

services.AddHealthChecksUI(setupSettings: setup =>
{
    setup.AddHealthCheckEndpoint("endpoint1", "http://localhost:5001/health");
});

再次檢視UI介面,就能看到對應的檢查項:

總結

本篇文章主要為大家介紹了 aspnet core 2.2之後所推出的“HealthCheck”,與使用傳統的Controller 公開API進行檢查不同,使用“IHealthCheck”能夠更快速的進行訪問(畢竟不需要進行模型繫結等操作),而且IHealthCheck介面能夠更好的進行檢查項擴充套件。讓我們能夠更快更清楚的瞭解到應用程式執行的情況。

當然,由於篇幅有限,本來還想繼續拓展IHealthCheckPublisher介面和健康檢查的實現原理等內容,就放在以後再說吧。如果您對該功能感興趣可以檢視 《ASP.NET Core 中的執行狀況檢查》和第三方HealthChecks擴充套件。

最後,偷偷說一句:創作不易,點個推薦吧.....