寫在前面
HealthCheck 不僅是對應用程式內執行情況、資料流通情況進行檢查, 還包括應用程式對外部服務或依賴資源的健康檢查。
健康檢查通常是以暴露應用程式的HTTP端點的形式 實施,可用於配置健康探測的的場景有 :
-
容器或負載均衡時 探測應用的狀態, 例如:容器探測到應用unhealthy可 終止後續的滾動部署或者重啟容器;負載均衡器探測到例項healthyunt能將請求路由到健康的執行例項。
-
對應用程式種依賴的第三方服務進行健康探測,比如redis、database、外部服務介面
-
記憶體、硬碟、網路等物理依賴資源的探測
HealthCheck提供一種 告知外部應用執行狀態的機制。
容器HEALTHCHECK指令
一般情況下我們很容易知道容器正在執行[running], 但容器作為相對獨立的應用執行環境,有時候並不知道容器是否以預期的方式正確運作[working]
Dockerfile/ docker-compose.yml檔案提供的 HEALTHCHECK指令提供了探測容器正確工作的輪訓機制,輪訓內容可由應用自身決定。
該指令定義輪詢引數interval、探測超時引數timeout、 重試引數retries 進行不間斷探測容器:
// 通過在容器內執行shell命令來探測容器健康狀態, 命令返回值0表示容器healthy, 命令返回值1表示unhealthy
EALTHCHECK [OPTIONS] CMD command
對於容器內Web應用,自然而然會想到使用暴露HTTP端點的方式去探測,並將error response認定為unhealthy
// 容器每隔5min請求應用程式的http://localhost(重試3次),成功響應則返回0,錯誤響應則返回1
HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMD curl -f http://localhost:5000/healthz || exit 1
下面我們會將漸進式演示 使用Docker平臺的HEALTHCHECK指令對接 ASP.NET Core程式的健康檢查能力。
ASP.NET Core 實現HealthCheck
ASPNET Core在2.2版本內建了健康檢查的能力, 使用的是一個HealthCheck Middleware, 該中介軟體是一個終端中介軟體,滿足該路徑的url請求,將會被該中介軟體處理。
public void ConfigureServices(IServiceCollection services) { services.AddHealthChecks(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseHealthChecks("/healthcheck"); }
請求/healthcheck端點, 程式會進行健康檢查邏輯並響應輸出, 預設的行為:
① 對healthy、degraded狀態返回200 OK 響應碼; 對於unhealthy返回503 Service Unavailable 響應碼
② 響應體只會包含簡單的HealthStatus列舉字串
③ 將每次健康檢查的結果寫入HealthReport物件。
作為企業級專案,存在對Web專案物理資源和服務依賴的健康檢查需求, 這裡我們為避免重複造輪子,引入了開源的力量。
開源社群對HealthCheck的支援
開源的企業級AspNetCore.Diagnostics.HealthChecks系列元件,該系列元件支援多種物理資源和服務依賴的健康檢查,支援報告推送,支援友好的檢查報告UI(支援後臺輪訓檢查)、支援webhook通知。
下面的步驟演示了對web程式HTTP請求、Redis、Sqlite等服務進行健康檢查的端點配置
① 引入AspNetCore.HealthChecks.Redis 、 AspNetCore.HealthChecks.Sqlite nuget庫
② startup中配置並啟用健康檢查
// 以下程式碼擷取自 Startup.ConfigureServices方法,對swagger服務地址、redis、sqlte進行健康檢查 services.AddHealthChecks().AddAsyncCheck("Http", async () => { using (HttpClient client = new HttpClient()) { try { var response = await client.GetAsync("http://localhost:5000/swagger"); if (!response.IsSuccessStatusCode) { throw new Exception("Url not responding with 200 OK"); } } catch (Exception) { return await Task.FromResult(HealthCheckResult.Unhealthy()); } } return await Task.FromResult(HealthCheckResult.Healthy()); }) .AddSqlite( sqliteConnectionString: Configuration.GetConnectionString("sqlite"), healthQuery: "select count(*) as count from ProfileUsageCounters;", name: "sqlite", failureStatus: HealthStatus.Degraded, tags: new string[] { "db", "sqlite", "sqlite" } ) .AddRedis(Configuration.GetConnectionString("redis"), "redis", HealthStatus.Unhealthy, new string[] { "redis", "redis" }) .Services .AddMvc(); // 以下程式碼擷取自Startup.Configure方法: 啟用/healthz作為檢查端點 app.UseHealthChecks("/healthz").UseMvcWithDefaultRoute(); // 這裡仍然只會響應 200/503狀態碼+簡單的HealthStatus列舉值
小技巧:你也可以使用UseHealthChecks()擴充套件方法修改預設的響應輸出, 這裡我們可引入HealthChecks.UI.Client nuget package輸出更加詳細的的HealthReport
app.UseHealthChecks("/healthz", new HealthCheckOptions() { Predicate = _ => true, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse // 該響應輸出是一個json,包含所有檢查項的詳細檢查結果 });
注意
上文在Dockerfile中配置的HEALTHCHECK 指令:
HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMD curl -f http://localhost:5000/healthz || exit 1
並不關注響應體輸出,依然對於success response 返回0, error response返回1。
測試容器的HEALTHCHECK輸出
使用docker ps命令可檢視容器的狀態, 通過docker inspect [container_id] 檢視容器HealthCheck的輸出
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0111ea10581f eqidmanager_proxy "nginx -g 'daemon ..." 24 hours ago Up 24 hours 0.0.0.0:80->80/tcp eqidmanager_proxy_1 8e96a0e8b993 eqidmanager_app "dotnet EqidManage..." 24 hours ago Up 24 hours (healthy) 80/tcp eqidmanager_app_1
容器在啟動的時候是starting, 一旦監測到成功的響應狀態碼,將會轉換為healthy 並將會持續間隔輪詢檢查。
附加知識點
拋開Docker的HEALTHCHECK指令,負載均衡器的輪詢健康檢查端點不談,我們的Web自身也可以配置輪詢健康檢查。
就我們上面的Web 例項來說,我們只對外提供的是一個 /healthcheck 檢查端點,可引入HealthChecks.UI.dll 將會在前端生成一個友好的HealthReport 介面, 該庫支援後臺輪詢檢查,支援webhook 通知。
這裡就不展開說明,自行前往AspNetCore.Diagnostics.HealthChecks檢視響應文件,效果如下:
至此,本文內容完畢:
- 使用ASP.NETCore 框架實現一個稍複雜的HealthCheck端點
- 使用docker的HEALTHCHECK 指令對接該端點的響應,(該能力是實現容器自愈的基礎, 請關注後續博文)。
感謝您的認真閱讀,如有問題請大膽斧正,如果您覺得本文對你有用,不妨幫忙點個或加關注。
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置註明本文的作者及原文連結,否則保留追究法律責任的權利。