【5min+】保持程序健康的秘訣!AspNetCore的HealthCheck

系列介紹

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

正文

在開發AspNet Core應用的時候,我們經?;崳糜τ霉家桓鎏厥獾?strong>檢測接口出來。該接口的目的很簡單,告訴某一些外界程序(比如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 之后,我們有了新的解決方式。只需要簡單的操作就可以進行程序運行狀況的檢查。

x

我們只需要在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" 路徑,將會看到對應結果:

x

如果程序正常,則返回Http狀態碼為200,顯示內容為"Healthy"的結果。如果程序不正常,則返回Http狀態碼為503,顯示內容為"UnHealthy"的結果。

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

為什么要自檢?

看到這里,可能有些同學要問:“我引入一個檢測到底有什么用?什么情況下我需要這么做呢?”

其實,對咱們的應用程序來說,做運行情況檢查是非常有必要的。

就好比去醫院看病的時候,醫生往往會問病人:“你現在是感覺哪兒不舒服,對哪些藥物過敏”等等問題。然后才能對癥下藥。

更形象的一個例子是做體檢:人們一般會自費花錢定期去醫院做體檢,如果發現哪一檢查項有異常的時候,就會報告給醫院并且去尋找對應的醫生,向醫生說明情況之后得到對應的治療方案。

所以咱們的應用程序也是一樣的,“定期體檢”有必要嗎? 肯定是有必要的。如果不定期體檢,我們很難知道現在程序運行狀態到底是什么樣子,或許它已經“瀕臨崩?!繃?,需要立即釋放內存。

還有一點就是:需要如實的報告檢查情況。就如同醫生問病人:“您哪不舒服?”,病人說:“我沒病。我哪兒都沒問題” 。 那醫生只會認為病人是來搞笑的,所以放棄對他的治療。

x

始終要相信一點,沒有人比你自己更懂你自己。雖然外界的程序也會有各種其它方式來判斷應用程序是否正常,但是它只能知道大概,只有程序體本身才能更清楚的知道現在運行的情況。

目的性的檢查

最初我們只是簡單的引入了 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)。

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

x

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

第三方支持

雖然官方為我們提供的運行檢查庫已經足夠輕量和簡單。但是為了避免重復造輪子,我們可以使用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:

x

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

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

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

x

總結

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

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

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

x

posted @ 2020-03-02 17:08  句幽  閱讀(...)  評論(...編輯  收藏