正文
在開發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.cs
的AddHealthChecks
進行擴展:
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界面