日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET Core 3.1之深入源码理解HealthCheck(二)

發布時間:2023/12/4 asp.net 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Core 3.1之深入源码理解HealthCheck(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫在前面

前文討論了HealthCheck的理論部分,本文將討論有關HealthCheck的應用內容。

  • 可以監視內存、磁盤和其他物理服務器資源的使用情況來了解是否處于正常狀態。

  • 運行狀況檢查可以測試應用的依賴項(如數據庫和外部服務終結點)以確認是否可用和正常工作。

  • 運行狀況探測可以由容器業務流程協調程序和負載均衡器用于檢查應用的狀態。

源碼研究

在應用中引入HealthCheck,一般需要配置Startup文件,如下所示:

public void ConfigureServices(IServiceCollection services) {services.AddHealthChecks(); }public void Configure(IApplicationBuilder app) {app.UseRouting();app.UseEndpoints(endpoints =>{endpoints.MapHealthChecks("/health");}); }

其中services.AddHealthChecks();會把我們引入到HealthCheckService的擴展方法中,代碼如下:

public static class HealthCheckServiceCollectionExtensions {public static IHealthChecksBuilder AddHealthChecks(this IServiceCollection services){services.TryAddSingleton<HealthCheckService, DefaultHealthCheckService>();services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, HealthCheckPublisherHostedService>());return new HealthChecksBuilder(services);} }

該擴展方法會嘗試注冊一個HealthCheckService的單例對象。HealthCheckService本身是一個抽象類,它內部含有一個抽象方法,主要用于執行健康檢查并返回健康狀態的聚合信息。抽象方法如下所示:

public abstract Task<HealthReport> CheckHealthAsync(Func<HealthCheckRegistration, bool> predicate,CancellationToken cancellationToken = default);

HealthCheckService有一個默認派生類,就是DefaultHealthCheckService,在其構造方法中,會去驗證是否有重復的健康檢查名稱存在,如果有,就會拋出異常。另外名稱的檢查是不區分大小寫的。該類所實現的抽象方法作為健康檢查的核心功能,內部實現還是比較復雜的。

首先我們看一下該方法的實現源碼:

public override async Task<HealthReport> CheckHealthAsync(Func<HealthCheckRegistration, bool> predicate,CancellationToken cancellationToken = default) {var registrations = _options.Value.Registrations;if (predicate != null){registrations = registrations.Where(predicate).ToArray();}var totalTime = ValueStopwatch.StartNew();Log.HealthCheckProcessingBegin(_logger);var tasks = new Task<HealthReportEntry>[registrations.Count];var index = 0;using (var scope = _scopeFactory.CreateScope()){foreach (var registration in registrations){tasks[index++] = Task.Run(() => RunCheckAsync(scope, registration, cancellationToken), cancellationToken);}await Task.WhenAll(tasks).ConfigureAwait(false);}index = 0;var entries = new Dictionary<string, HealthReportEntry>(StringComparer.OrdinalIgnoreCase);foreach (var registration in registrations){entries[registration.Name] = tasks[index++].Result;}var totalElapsedTime = totalTime.GetElapsedTime();var report = new HealthReport(entries, totalElapsedTime);Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime);return report; }

1、其內部有比較完善的監控機制,會在內部維護了一個Log功能,全程監控健康檢查的耗時,該日志所記錄的健康檢查不僅僅是一個健康檢查集合的耗時,而且也記錄了每個Name的耗時。

2、該方法會通過await Task.WhenAll(tasks).ConfigureAwait(false);并發執行健康檢查。當然,我需要注意的是,過多的健康檢查任務將會導致系統性能的下降,這主要看如何取舍了

CheckHealthAsync內部還會調用一個私有方法RunCheckAsync,這是真正執行健康檢查的方法。RunCheckAsync方法執行完成后,會創建HealthReportEntry對象返回到CheckHealthAsync中,并組裝到HealthReport對象中,到此該抽象方法執行完畢。

以下是RunCheckAsync方法的源碼:

private async Task<HealthReportEntry> RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration, CancellationToken cancellationToken) {cancellationToken.ThrowIfCancellationRequested();var healthCheck = registration.Factory(scope.ServiceProvider);using (_logger.BeginScope(new HealthCheckLogScope(registration.Name))){var stopwatch = ValueStopwatch.StartNew();var context = new HealthCheckContext { Registration = registration };Log.HealthCheckBegin(_logger, registration);HealthReportEntry entry;CancellationTokenSource timeoutCancellationTokenSource = null;try{HealthCheckResult result;var checkCancellationToken = cancellationToken;if (registration.Timeout > TimeSpan.Zero){timeoutCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);timeoutCancellationTokenSource.CancelAfter(registration.Timeout);checkCancellationToken = timeoutCancellationTokenSource.Token;}result = await healthCheck.CheckHealthAsync(context, checkCancellationToken).ConfigureAwait(false);var duration = stopwatch.GetElapsedTime();entry = new HealthReportEntry(status: result.Status,description: result.Description,duration: duration,exception: result.Exception,data: result.Data,tags: registration.Tags);Log.HealthCheckEnd(_logger, registration, entry, duration);Log.HealthCheckData(_logger, registration, entry);}catch (OperationCanceledException ex) when (!cancellationToken.IsCancellationRequested){var duration = stopwatch.GetElapsedTime();entry = new HealthReportEntry(status: HealthStatus.Unhealthy,description: "A timeout occured while running check.",duration: duration,exception: ex,data: null);Log.HealthCheckError(_logger, registration, ex, duration);}// Allow cancellation to propagate if it's not a timeout.catch (Exception ex) when (ex as OperationCanceledException == null){var duration = stopwatch.GetElapsedTime();entry = new HealthReportEntry(status: HealthStatus.Unhealthy,description: ex.Message,duration: duration,exception: ex,data: null);Log.HealthCheckError(_logger, registration, ex, duration);}finally{timeoutCancellationTokenSource?.Dispose();}return entry;} }

來自官方的應用

  • 數據庫探測,例子可以是執行select 1 from tableName根據數據庫響應來判斷是否健康

  • Entity Framework Core DbContext 探測,DbContext?檢查確認應用可以與為 EF Core?DbContext?配置的數據庫通信。

  • 單獨的就緒情況和運行情況探測,在某些托管方案中,可能初始化是一個比較耗時的操作,應用正常運行,但是可能還不能正常處理請求并響應

  • 具有自定義響應編寫器的基于指標的探測,比如檢查內存占用是否超標,cpu 是否占用過高,連接數是否達到上限

  • 按端口篩選,指定端口,一般用于容器環境,根據容器啟動時配置的端口號進行響應

  • 分發運行狀況檢查庫,將檢查接口實現獨立一個類,并通過依賴注入獲取參數,檢查時根據參數編寫邏輯

  • 運行狀況檢查發布服務器,如果向 DI 添加 IHealthCheckPublisher,則運行狀態檢查系統將定期執行狀態檢查,并使用結果調用 PublishAsync。適用于需要推送的健康系統,而不是健康系統

  • 使用 MapWhen 限制運行狀況檢查,使用 MapWhen 對運行狀況檢查終結點的請求管道進行條件分支

其他更多內容請參考:https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-3.1

總結

以上是生活随笔為你收集整理的.NET Core 3.1之深入源码理解HealthCheck(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。