资源监视

资源监视涉及持续测量资源利用率值,例如 CPU、内存和网络使用情况。 Microsoft.Extensions.Diagnostics.ResourceMonitoring NuGet 包提供了一系列定制 API,专用于监视 .NET 应用程序的资源利用率。

可以采用两种方式使用度量值:

重要说明

Microsoft.Extensions.Diagnostics.ResourceMonitoring 包会假定使用者将向 Microsoft.Extensions.Logging 包注册日志记录提供程序。 如果未注册日志记录,则调用 AddResourceMonitoring 将引发异常。 此外,按照指南配置类别的Debug日志级别Microsoft.Extensions.Diagnostics.ResourceMonitoring,可以启用内部库日志记录。

使用资源监视的 .NET 指标

若要使用资源监视库生成的 .NET 指标,请执行以下操作:

  1. Microsoft.Extensions.Diagnostics.ResourceMonitoring 包添加到项目。

  2. 将资源监视服务添加到依赖项注入容器:

    services.AddResourceMonitoring();
    
  3. 使用任何与 OpenTelemetry 兼容的指标收集器配置指标集合。 例如:

    services.AddOpenTelemetry()
        .WithMetrics(builder =>
        {
            builder.AddMeter("Microsoft.Extensions.Diagnostics.ResourceMonitoring");
            builder.AddConsoleExporter(); // Or any other metrics exporter
        });
    
  4. 现在,可以通过配置的指标导出程序观察资源使用情况指标。

有关可用指标的信息,请参阅 .NET 扩展指标:Microsoft.Extensions.Diagnostics.ResourceMonitoring

有关指标集合的信息,请参阅 指标集合

使用 IResourceMonitor 接口

谨慎

IResourceMonitor本节中所述的接口已弃用,可能会在 .NET 的未来版本中删除。 迁移到基于指标的方法

IResourceMonitor 接口提供了用于检索有关进程资源利用率的实时信息的方法。 此接口支持检索与 CPU 和内存使用情况相关的数据,并且当前与 Windows 和 Linux 平台兼容。

示例资源监视使用情况

以下示例演示了如何使用 IResourceMonitor 接口检索有关当前进程的 CPU 和内存使用情况的信息。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.ResourceMonitoring;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Spectre.Console;

var app = Host.CreateDefaultBuilder()
    .ConfigureServices(services =>
    {
        services.AddLogging(static builder => builder.AddConsole())
                .AddResourceMonitoring();
    })
    .Build();

var monitor = app.Services.GetRequiredService<IResourceMonitor>();
await app.StartAsync();

前面的代码:

此时,使用 IResourceMonitor 实现时,将使用 IResourceMonitor.GetUtilization 方法请求资源利用率。 GetUtilization 方法会返回 ResourceUtilization 实例,其中包含以下信息:

使用 Spectre.Console 扩展资源监视

扩展此示例后,可以利用 Spectre.Console,这是一个备受推崇的 .NET 库,旨在简化具有视觉吸引力的跨平台控制台应用程序的开发。 借助 Spectre,你将能够以表格格式呈现资源利用率数据。 以下代码演示了如何使用 IResourceMonitor 接口访问有关当前进程的 CPU 和内存使用情况的详细信息,然后在表中显示此数据:

await StartMonitoringAsync(monitor, token);

async Task StartMonitoringAsync(IResourceMonitor monitor, CancellationToken cancellationToken)
{
    var table = new Table()
        .Centered()
        .Title("Resource Monitoring", new Style(foreground: Color.Purple, decoration: Decoration.Bold))
        .Caption("Updates every three seconds. *GTD: Guaranteed ", new Style(decoration: Decoration.Dim))
        .RoundedBorder()
        .BorderColor(Color.Cyan1)
        .AddColumns(
        [
            new TableColumn("Time").Centered(),
            new TableColumn("CPU %").Centered(),
            new TableColumn("Memory %").Centered(),
            new TableColumn("Memory (bytes)").Centered(),
            new TableColumn("GTD / Max Memory (bytes)").Centered(),
            new TableColumn("GTD / Max CPU (units)").Centered(),
        ]);

    await AnsiConsole.Live(table)
        .StartAsync(async ctx =>
        {
            var window = TimeSpan.FromSeconds(3);
            while (cancellationToken.IsCancellationRequested is false)
            {
                var utilization = monitor.GetUtilization(window);
                var resources = utilization.SystemResources;

                table.AddRow(
                    [
                        $"{DateTime.Now:T}",
                        $"{utilization.CpuUsedPercentage:p}",
                        $"{utilization.MemoryUsedPercentage:p}",
                        $"{utilization.MemoryUsedInBytes:#,#}",
                        $"{resources.GuaranteedMemoryInBytes:#,#} / {resources.MaximumMemoryInBytes:#,#}",
                        $"{resources.GuaranteedCpuUnits} / {resources.MaximumCpuUnits}",
                    ]);

                ctx.Refresh();
                await Task.Delay(window);
            }
        });
}

前面的代码:

  • 创建取消令牌源和取消令牌。
  • 创建一个新 Table 实例,并使用标题、描述文字和列对其进行配置。
  • 执行 Table 实例的实时呈现,从而传入每三秒调用一次的委托。
  • IResourceMonitor 实例获取当前资源利用率信息,并将其显示为 Table 实例中的新行。

下面是上述代码的输出示例:

示例资源监视应用输出。

有关此示例的源代码,请参阅资源监视示例

迁移到基于指标的资源监视

由于 IResourceMonitor 接口已被弃用,因此请迁移到基于指标的方法。 Microsoft.Extensions.Diagnostics.ResourceMonitoring 包提供多个可改用的指标,例如:

  • container.cpu.limit.utilization:正在运行的容器化应用程序的 CPU 消耗份额,相对于 [0, 1] 范围内的资源限制。 适用于 Linux 和 Windows 上的容器化应用。
  • container.cpu.request.utilization:正在运行的容器化应用程序的 CPU 消耗份额相对于 [0, 1] 范围内的资源请求。 适用于 Linux 上的容器化应用。
  • container.memory.limit.utilization:正在运行的容器化应用程序的内存消耗份额相对于范围 [0, 1]中的资源限制。 适用于 Linux 和 Windows 上的容器化应用。

有关可用指标的详细信息,请参阅 内置指标:Microsoft.Extensions.Diagnostics.ResourceMonitoring 部分。

迁移指南

本部分提供从已弃用 IResourceMonitor 的接口到基于指标的方法的迁移指南。 仅当手动侦听应用程序中的资源利用率指标时,才需要本指南。 在大多数情况下,无需手动侦听指标,因为它们是使用指标导出程序自动收集和导出到后端的,如 使用资源监视的 .NET 指标中所述。

如果有类似于 IResourceMonitor示例用法的代码,请按如下所示更新它:

await StartMonitoringAsync(logger, token);

async Task StartMonitoringAsync(ILogger logger, CancellationToken cancellationToken)
{
    var table = new Table()
        .Centered()
        .Title("Resource Monitoring", new Style(foreground: Color.Purple, decoration: Decoration.Bold))
        .RoundedBorder()
        .BorderColor(Color.Cyan1)
        .AddColumns(
        [
            new TableColumn("Time").Centered(),
            new TableColumn("CPU limit %").Centered(),
            new TableColumn("CPU request %").Centered(),
            new TableColumn("Memory limit %").Centered(),
        ]);

    const string rmMeterName = "Microsoft.Extensions.Diagnostics.ResourceMonitoring";
    using var meter = new Meter(rmMeterName);
    using var meterListener = new MeterListener
    {
        InstrumentPublished = (instrument, listener) =>
        {
            if (instrument.Meter.Name == rmMeterName &&
                instrument.Name.StartsWith("container."))
            {
                listener.EnableMeasurementEvents(instrument, null);
            }
        }
    };
    
    var samples = new Dictionary<string, double>();
    meterListener.SetMeasurementEventCallback<double>((instrument, value, _, _) =>
    {
        if (instrument.Meter.Name == rmMeterName)
        {
            samples[instrument.Name] = value;
        }
    });
    meterListener.Start();

    await AnsiConsole.Live(table)
        .StartAsync(async ctx =>
        {
            var window = TimeSpan.FromSeconds(5);
            while (cancellationToken.IsCancellationRequested is false)
            {
                meterListener.RecordObservableInstruments();

                table.AddRow(
                    [
                        $"{DateTime.Now:T}",
                        $"{samples["container.cpu.limit.utilization"]:p}",
                        $"{samples["container.cpu.request.utilization"]:p}",
                        $"{samples["container.memory.limit.utilization"]:p}",
                    ]);

                ctx.Refresh();

                await Task.Delay(window);
            }
        });
}

前面的代码:

  • 创建取消令牌源和取消令牌。
  • 创建一个新 Table 实例,并使用标题、描述文字和列对其进行配置。
  • 执行 Table 实例的实时呈现,从而传入每三秒调用一次的委托。
  • 使用具有该方法的回调集 SetMeasurementEventCallback 获取当前资源利用率信息,并将其显示为实例中的 Table 新行。

下面是上述代码的输出示例:

使用手动指标应用输出的示例资源监视。

有关此示例的完整源代码,请参阅 使用手动指标示例进行资源监视

Kubernetes 探测

除了资源监视之外,存在于 Kubernetes 群集中的应用还会通过诊断探测来报告其运行状况。 Microsoft.Extensions.Diagnostics.Probes NuGet 包为 Kubernetes 探测提供支持。 它会外部化各种运行状况检查,以便与各种 Kubernetes 探测保持一致,例如:

  • 运行情况
  • 就绪
  • 启动

该库将应用的当前运行状况传达给 Kubernetes 托管环境。 如果进程报告处于不正常状态,Kubernetes 不会向其发送任何流量,从而提供恢复或终止的进程时间。

要添加对 Kubernetes 探测的支持,请添加对 Microsoft.Extensions.Diagnostics.Probes 的包引用。 在 IServiceCollection 实例上,调用 AddKubernetesProbes

另请参阅