文章目錄
使用 ASP.NET Core middleware 進行 gRPC healthy check
這個需求來自於某次的 issue:有個 service 的回應時好時壞,沒有規律,這讓我想起當年在壽險公司資訊部門使用 asp 提供服務的故事,當時也是出現相同的徵兆:雖然兩者相差十幾年、技術也天差地北,但同樣的服務都有時正常有時錯誤
後續 debug 過程中歸納出兩者都有提供多個 serrvice instance:目前專案是透過 kubernetes 設定 3 個 pods,而之前壽險公司是有 8 組 iis 提供服務,時好時壞是因為只有部份 service instance 有問題,之前懷疑過程式版本不一致,但目前系統都是以 image 做為 deploy 的基礎單位,暫時排除,加上重啟該 service instance 後就會正常,不過實際真正造成問題的原因還是沒找到:每次遇到這問題時都是異常已造成使用者問題沒有充足時間慢慢 debug
因為每次遇到這狀況都是 restart service 讓服務恢復正常,所以就想讓重啟這件事變成自動化,而在那之前最重要的就是辨別出異常,立馬來看看可以怎麼做吧
基本環境說明
- Azure VM 標準 B2s (2 vcpu,4 GiB 記憶體)
- Windows 10 version 1809 (OS Build 17763.1397)
- .NET Core SDK 3.1.401
- 預設 gRPC Server 專案範本
設定方式
調整 proto 產出的程式碼方式為
Both
預設為
Server
透過 IHealthCheck 實做 grpc check
這邊透過 di 取得預設範本中的 gRPC client
public class GreeterHealthChecker : IHealthCheck { private readonly Greeter.GreeterClient _client; public GreeterHealthChecker(Greeter.GreeterClient client) { _client = client; } public async Task<HealthCheckResult> CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken)) { //以下就是自訂檢查邏輯 var reply = await _client.SayHelloAsync( new HelloRequest {Name = "GreeterClient"}); if ( reply.Message == "Hello GreeterClient") { return HealthCheckResult.Healthy("A healthy result."); } return HealthCheckResult.Unhealthy("An unhealthy result."); } }
註冊 health check
Startup.cs
的ConfigureServices
加上services.AddHealthChecks();
public class Startup { public void ConfigureServices(IServiceCollection services) { //....其他需要註冊 //將上方自訂 health check 方法加至 health check 檢查中 services.AddHealthChecks().AddCheck<GreeterHealthChecker>("GRPC_health_check"); } }
註冊 gRPC client
Startup.cs
的ConfigureServices
加上services.AddGrpcClient();
public class Startup { public void ConfigureServices(IServiceCollection services) { //....其他需要註冊 //將上方自訂 health check 方法加至 health check 檢查中 services.AddHealthChecks().AddCheck<GreeterHealthChecker>("GRPC_health_check"); //將本身提供 gRPC 服務的 endpoint 加至 gRPC client factory 中 services.AddGrpcClient<Greeter.GreeterClient>(o => { o.Address = new Uri("https://localhost:5001"); }); } }
加上提供查詢 health check 結果的 endpoint
Startup.cs
的Configure
加上endpoints.MapHealthChecks("/health");
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { // 提供查詢 health checks 結果的 endpoint endpoints.MapHealthChecks("/health"); endpoints.MapGrpcService<GreeterService>(); endpoints.MapGet("/", async context => { await context.Response.WriteAsync( "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); }); }); }
實際效果
心得
現在團隊的主力開發環境是 macOS,但今天紀錄的這個做法在 macOS 上會失效,錯誤的緣頭是 aspsettings.json 中的 Kestrel.EndpointDefaults.Protocols="Http2"
至於原因我猜測與之前筆記 ASP.NET Core gRPC 無法在 macOS 上啟動?! 提到的 macOS 不支援具有 TLS 的 ASP.NET Core gRPC 服務有關:只要啟用了 Kestrel.EndpointDefaults.Protocols="Http2"
ASP.NET Core 中的 http endpoint 就無法正確存取,但這問題這麼大不可能沒人反應呀,我覺得可能是我設定的問題
錯誤畫面如下:
相同程式碼在 Windows 下的畫面
有看到其他做法,這幾日有空再嘗試看看,敬請期待
完整程式碼請參考:yowko/GrpcHealthCheck
參考資訊
文章作者 Yowko Tsai
上次更新 2020-12-11
授權合約
本部落格 (Yowko's Notes) 所有的文章內容(包含圖片),任何轉載行為,必須通知並獲本部落格作者 (Yowko Tsai) 的同意始得轉載,且轉載皆須註明出處與作者。
Yowko's Notes 由 Yowko Tsai 製作,以創用CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款 釋出。