Sdílet prostřednictvím


Síťové metriky v .NET

Metriky jsou číselná měření hlášená v průběhu času. Obvykle se používají ke sledování stavu aplikace a generování výstrah.

Počínaje rozhraním .NET 8 se System.Net.Http a komponenty System.Net.NameResolution instrumentují k publikování metrik pomocí . Nová rozhraní API system.Diagnostics.Metrics rozhraní NET. Tyto metriky byly navrženy ve spolupráci s OpenTelemetry, aby byly konzistentní se standardem a dobře fungovaly s oblíbenými nástroji, jako jsou Prometheus a Grafana. Jsou také multidimenzionální, což znamená, že měření jsou přidružená ke párům klíč-hodnota označovaným také jako značky (označované také jako atributy nebo popisky). Značky umožňují kategorizaci měření, která pomáhá analyzovat.

Spropitné

Pro úplný seznam všech vestavěných nástrojů a jejich atributů se podívejte na metriky systému System.Net.

Shromažďování metrik System.Net

Aby bylo možné využít integrované instrumentace metrik, musí být aplikace .NET nakonfigurovaná tak, aby tyto metriky shromažďovala. To obvykle znamená jejich transformaci pro externí úložiště a analýzu, například na systémy monitorování.

Existuje několik způsobů, jak shromažďovat síťové metriky v .NET.

  • Rychlý přehled pomocí jednoduchého samostatného příkladu najdete v tématu Shromažďování metrik pomocí čítačů dotnet.
  • Pro shromažďování a monitorování metrik produkčním časem můžete použít Grafana s OpenTelemetry a Prometheus nebo Azure Monitor Application Insights. Tyto nástroje ale můžou být kvůli složitosti nevhodné k použití v době vývoje.
  • Pro shromažďování metrik a řešení potíží čase vývoje doporučujeme použít rozhraní .NET Aspire, která poskytuje jednoduchý, ale rozšiřitelný způsob, jak začít s metrikami a distribuované trasování ve vaší aplikaci a diagnostikovat problémy místně.
  • Je také možné opakovaně používat projekt Výchozí nastavení služby Aspire bez orchestrace Aspire, což je užitečný způsob, jak do svého projektu ASP.NET začlenit rozhraní API pro sledování a konfiguraci metrik OpenTelemetry.

Shromažďování metrik pomocí čítačů dotnet

dotnet-counters je multiplatformní nástroj příkazového řádku pro ad hoc zkoumání metrik .NET a šetření výkonu na první úrovni.

Pro účely tohoto kurzu vytvořte aplikaci, která paralelně odesílá požadavky HTTP na různé koncové body.

dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics

Nahraďte obsah Program.cs následujícím vzorovým kódem:

using System.Net;

string[] uris = ["http://example.com", "http://httpbin.org/get", "https://example.com", "https://httpbin.org/get"];
using HttpClient client = new()
{
    DefaultRequestVersion = HttpVersion.Version20
};

Console.WriteLine("Press any key to start.");
Console.ReadKey();

while (!Console.KeyAvailable)
{
    await Parallel.ForAsync(0, Random.Shared.Next(20), async (_, ct) =>
    {
        string uri = uris[Random.Shared.Next(uris.Length)];
        try
        {
            byte[] bytes = await client.GetByteArrayAsync(uri, ct);
            await Console.Out.WriteLineAsync($"{uri} - received {bytes.Length} bytes.");
        }
        catch { await Console.Out.WriteLineAsync($"{uri} - failed."); }
    });
}

Ujistěte se, že je nainstalovaný dotnet-counters:

dotnet tool install --global dotnet-counters

Spusťte aplikaci HelloBuiltinMetrics.

dotnet run -c Release

Spusťte dotnet-counters v samostatném okně rozhraní příkazového řádku a zadejte název procesu a měřiče, které chcete sledovat, a pak stiskněte klávesu v aplikaci HelloBuiltinMetrics, aby začal odesílat požadavky. Jakmile se měření spustí, dotnet-counters konzolu průběžně aktualizuje nejnovějšími čísly:

dotnet-counters monitor --counters System.Net.Http,System.Net.NameResolution -n HelloBuiltinMetrics

výstup nástroje dotnet-counters

Shromažďování metrik pomocí rozhraní .NET Aspire

Jednoduchým způsobem, jak shromažďovat trasování a metriky v ASP.NET aplikacích, je použít .NET Aspire. .NET Aspire je sada rozšíření .NET, která usnadňují vytváření a práci s distribuovanými aplikacemi. Jednou z výhod použití rozhraní .NET Aspire je, že telemetrie je integrovaná pomocí knihoven OpenTelemetry pro .NET.

Výchozí šablony projektů pro .NET Aspire obsahují ServiceDefaults projekt. Každá služba v řešení .NET Aspire má odkaz na projekt Výchozí služby. Služby ji používají k nastavení a konfiguraci OTelu.

Šablona projektu Výchozí nastavení služby zahrnuje balíčky OTel SDK, ASP.NET, HttpClient a Runtime Instrumentation. Tyto komponenty instrumentace jsou nakonfigurovány v souboru Extensions.cs. Pro podporu vizualizace telemetrie na řídicím panelu Aspire zahrnuje projekt Výchozí nastavení služby také ve výchozím nastavení exportér OTLP.

Řídicí panel Aspire je navržen tak, aby umožnil pozorování telemetrie v rámci místního ladicího cyklu, což vývojářům umožňuje zajistit, že aplikace generují telemetrická data. Vizualizace telemetrie také pomáhá diagnostikovat tyto aplikace místně. Schopnost sledovat volání mezi službami je stejně užitečná v době ladění jako v produkčním prostředí. Řídicí panel .NET Aspire se spustí automaticky při F5 projektu AppHost ze sady Visual Studio nebo dotnet run projektu AppHost z příkazového řádku.

Rychlý návod

  1. Pomocí dotnet newvytvořte startovací aplikaci .NET Aspire 9.

    dotnet new aspire-starter-9 --output AspireDemo
    

    Nebo ve Visual Studiu vytvořte nový projekt a vyberte šablonu úvodní aplikace .NET Aspire 9:

    Vytvoření startovací aplikace .NET Aspire 9 ve Visual Studiu

  2. Otevřete Extensions.cs v projektu ServiceDefaults a posuňte se k metodě ConfigureOpenTelemetry. Všimněte si volání AddHttpClientInstrumentation(), které se přihlašuje k síťovým měřičům.

    .WithMetrics(metrics =>
    {
        metrics.AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddRuntimeInstrumentation();
    })
    

    Všimněte si, že v rozhraní .NET 8 nebo novějších je možné AddHttpClientInstrumentation() nahradit ručními předplatnými měřičů:

    .WithMetrics(metrics =>
    {
        metrics.AddAspNetCoreInstrumentation()
            .AddMeter("System.Net.Http")
            .AddMeter("System.Net.NameResolution")
            .AddRuntimeInstrumentation();
    })
    
  3. Spusťte projekt AppHost. Tím by se měl spustit řídicí panel Aspire.

  4. Přejděte na stránku Počasí aplikace webfrontend a vygenerujte HttpClient žádost o apiservice. Aktualizujte stránku několikrát, aby se odeslalo více požadavků.

  5. Vraťte se na řídicí panel, přejděte na stránku Metriky a vyberte prostředek webfrontend. Posouváním dolů byste měli být schopni procházet předdefinované metriky System.Net.

    metriky sítě na řídicím panelu Aspire

Další informace o rozhraní .NET Aspire najdete tady:

Opětovné použití projektu Výchozí nastavení služby bez orchestrace .NET Aspire

Projekt Aspire Service Defaults poskytuje snadný způsob konfigurace OTel pro ASP.NET projekty, i v případě, že nepoužíváte zbytek rozhraní .NET Aspire, jako je AppHost pro orchestraci. Projekt Výchozí nastavení služby je k dispozici jako šablona projektu prostřednictvím sady Visual Studio nebo dotnet new. Nakonfiguruje OTel a nastaví exportér OTLP. Pak můžete použít proměnné prostředí OTel k nastavení koncového bodu OTLP pro odesílání telemetrie a k nastavení vlastností prostředků aplikace.

Postup použití ServiceDefaults mimo rozhraní .NET Aspire:

  1. Přidejte do řešení projekt ServiceDefaults pomocí příkazu Přidat nový projekt v sadě Visual Studio nebo použijte dotnet new:

    dotnet new aspire-servicedefaults --output ServiceDefaults
    
  2. Odkazujte na projekt ServiceDefaults z aplikace ASP.NET. V sadě Visual Studio vyberte Přidat>odkaz projektu a vyberte projekt ServiceDefaults

  3. Jako součást inicializace tvůrce aplikací volejte funkci nastavení OpenTelemetry ConfigureOpenTelemetry().

    var builder = WebApplication.CreateBuilder(args)
    builder.ConfigureOpenTelemetry(); // Extension method from ServiceDefaults.
    var app = builder.Build();
    app.MapGet("/", () => "Hello World!");
    app.Run();
    

Úplný návod najdete v Příklad: Použití OpenTelemetry s OTLP a samostatného řídicího panelu Aspire.

Zobrazení metrik v Grafaně pomocí OpenTelemetry a Prometheus

Pokud chcete zjistit, jak připojit ukázkovou aplikaci s aplikací Prometheus a Grafana, postupujte podle návodu v Použití OpenTelemetry s aplikací Prometheus, Grafana a Jaeger.

Pokud chcete zdůraznit HttpClient odesláním paralelních požadavků do různých koncových bodů, rozšiřte ukázkovou aplikaci o následující koncový bod:

app.MapGet("/ClientStress", async Task<string> (ILogger<Program> logger, HttpClient client) =>
{
    string[] uris = ["http://example.com", "http://httpbin.org/get", "https://example.com", "https://httpbin.org/get"];
    await Parallel.ForAsync(0, 50, async (_, ct) =>
    {
        string uri = uris[Random.Shared.Next(uris.Length)];

        try
        {
            await client.GetAsync(uri, ct);
            logger.LogInformation($"{uri} - done.");
        }
        catch { logger.LogInformation($"{uri} - failed."); }
    });
    return "Sent 50 requests to example.com and httpbin.org.";
});

Výběrem ikony + na horním panelu nástrojů a následným výběrem řídicího paneluvytvořte řídicí panel Grafana. V zobrazeném editoru řídicího panelu zadejte Otevřít připojení HTTP/1.1 do pole Název a do pole výrazu PromQL zadejte následující dotaz:

sum by(http_connection_state) (http_client_open_connections{network_protocol_version="1.1"})

Vyberte Použít pro uložení a zobrazení nového řídicího panelu. Zobrazí počet aktivních a nečinných připojení HTTP/1.1 ve fondu.

Připojení HTTP/1.1 v Grafana

Obohacení

Obohacení je přidání vlastních štítků (označovaných také jako atributy nebo popisky) k metrice. To je užitečné v případě, že aplikace chce přidat vlastní kategorizaci na řídicí panely nebo výstrahy vytvořené pomocí metrik. Nástroj http.client.request.duration podporuje obohacení registrací zpětných volání u HttpMetricsEnrichmentContext. Upozorňujeme, že se jedná o nízkoúrovňové API a pro každou HttpRequestMessageje nutná samostatná registrace zpětného volání.

Jednoduchým způsobem provedení registrace zpětného volání na jednom místě je implementace vlastního DelegatingHandler. To vám umožní zachytávat a upravovat požadavky před jejich předáním do vnitřního správce a odesláním na server.

using System.Net.Http.Metrics;

using HttpClient client = new(new EnrichmentHandler() { InnerHandler = new HttpClientHandler() });

await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");

sealed class EnrichmentHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpMetricsEnrichmentContext.AddCallback(request, static context =>
        {
            if (context.Response is not null) // Response is null when an exception occurs.
            {
                // Use any information available on the request or the response to emit custom tags.
                string? value = context.Response.Headers.GetValues("Enrichment-Value").FirstOrDefault();
                if (value != null)
                {
                    context.AddCustomTag("enrichment_value", value);
                }
            }
        });
        return base.SendAsync(request, cancellationToken);
    }
}

Pokud pracujete s IHttpClientFactory, můžete AddHttpMessageHandler použít k registraci EnrichmentHandler:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Net.Http.Metrics;

ServiceCollection services = new();
services.AddHttpClient(Options.DefaultName).AddHttpMessageHandler(() => new EnrichmentHandler());

ServiceProvider serviceProvider = services.BuildServiceProvider();
HttpClient client = serviceProvider.GetRequiredService<HttpClient>();

await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");

Poznámka

Z důvodů výkonu se zpětné volání pro obohacení vyvolá pouze v případě, že je povolen nástroj http.client.request.duration, což znamená, že by měly být shromažďovány metriky. Může to být dotnet-monitor, Prometheus Exporter, MeterListenernebo MetricCollector<T>.

integrace IMeterFactory a IHttpClientFactory

Metriky HTTP byly navrženy s ohledem na izolaci a testovatelnost. Tyto aspekty jsou podporovány použitím IMeterFactory, což umožňuje publikování metrik pomocí vlastní instance Meter, aby měřiče zůstaly izolované od sebe navzájem. Ve výchozím nastavení se k vysílání všech metrik používá globální Meter. Toto Meter je interní k knihovně System.Net.Http. Toto chování lze přepsat přiřazením vlastní instance IMeterFactory k SocketsHttpHandler.MeterFactory nebo HttpClientHandler.MeterFactory.

Poznámka

Meter.Name je System.Net.Http pro všechny metriky generované HttpClientHandler a SocketsHttpHandler.

Při práci s Microsoft.Extensions.Http a IHttpClientFactory v rozhraní .NET 8 nebo novějším se výchozí implementace IHttpClientFactory automaticky vybere instanci IMeterFactory zaregistrovanou v IServiceCollection a přiřadí ji primární obslužné rutině, která vytvoří interně.

Poznámka

Počínaje rozhraním .NET 8 metoda AddHttpClient automaticky volá AddMetrics k inicializaci služeb metrik a registraci výchozí implementace IMeterFactory pomocí IServiceCollection. Výchozí IMeterFactory ukládá Meter instance podle názvu, což znamená, že existuje jeden Meter s názvem System.Net.Http na IServiceCollection.

Testování metrik

Následující příklad ukazuje, jak ověřit integrované metriky v testech jednotek pomocí xUnit, IHttpClientFactorya MetricCollector<T> z balíčku NuGet Microsoft.Extensions.Diagnostics.Testing:

[Fact]
public async Task RequestDurationTest()
{
    // Arrange
    ServiceCollection services = new();
    services.AddHttpClient();
    ServiceProvider serviceProvider = services.BuildServiceProvider();
    var meterFactory = serviceProvider.GetService<IMeterFactory>();
    var collector = new MetricCollector<double>(meterFactory,
        "System.Net.Http", "http.client.request.duration");
    var client = serviceProvider.GetRequiredService<HttpClient>();

    // Act
    await client.GetStringAsync("http://example.com");

    // Assert
    await collector.WaitForMeasurementsAsync(minCount: 1).WaitAsync(TimeSpan.FromSeconds(5));
    Assert.Collection(collector.GetMeasurementSnapshot(),
        measurement =>
        {
            Assert.Equal("http", measurement.Tags["url.scheme"]);
            Assert.Equal("GET", measurement.Tags["http.request.method"]);
        });
}

Metriky vs. Počítadla událostí

Metriky jsou bohatší na funkce než EventCounters, zejména kvůli jejich multidimenzionální povaze. Tato multidimenzionální funkce umožňuje vytvářet sofistikované dotazy v nástrojích, jako je Prometheus, a získat přehledy na úrovni, která není možná u EventCounters.

V případě rozhraní .NET 8 se však instrumentují pouze System.Net.Http a komponenty System.Net.NameResolutions pomocí metrik, což znamená, že pokud potřebujete čítače z nižších úrovní zásobníku, jako je System.Net.Sockets nebo System.Net.Security, musíte použít EventCounters.

Kromě toho existují některé sémantické rozdíly mezi metrikami a jejich odpovídajícími hodnotami EventCounters. Například při použití HttpCompletionOption.ResponseContentReadcurrent-requests EventCounter považuje požadavek za aktivní až do okamžiku, kdy se přečte poslední bajt textu požadavku. Jeho protějšk metrik http.client.active_requests nezahrnuje čas strávený čtením textu odpovědi při počítání aktivních požadavků.

Potřebujete další metriky?

Pokud máte návrhy na další užitečné informace, které by mohly být zpřístupněny prostřednictvím metrik, vytvořte problém dotnet/runtime.