Megosztás a következőn keresztül:


Hálózati metrikák a .NET-ben

A metrikák az idő múlásával jelentett numerikus mérések. Ezek általában egy alkalmazás állapotának figyelésére és riasztások létrehozására szolgálnak.

A .NET 8-tól kezdve a System.Net.Http metrikák közzétételéhez az összetevőket és az System.Net.NameResolution összetevőket a rendszer a .NET 8 használatával teszi közzé. A NET új System.Diagnostics.Metrics API-ja. Ezek a metrikák az OpenTelemetryvel együttműködve lettek kialakítva, hogy összhangban legyenek a szabványokkal, és jól működjenek olyan népszerű eszközökkel, mint a Prometheus és a Grafana. Ezek többdimenziósak is, ami azt jelenti, hogy a mérések olyan kulcs-érték párokhoz vannak társítva, amelyeket címkéknek (más néven attribútumoknak vagy címkéknek) neveznek, amelyek lehetővé teszik az adatok elemzésére való kategorizálását.

Tipp.

Az összes beépített eszköz és attribútumaik átfogó listájáért tekintse meg System.Net metrikákat.

System.Net metrikák gyűjtése

A .NET-alkalmazásokban két részből áll a metrikák használata:

  • Rendszerezés: A .NET-kódtárakban lévő kód méréseket végez, és ezeket a méréseket egy metrikanévvel társítja. A .NET és a ASP.NET Core számos beépített metrikát tartalmaz.
  • Gyűjtemény: A .NET-alkalmazás úgy konfigurálja az elnevezett metrikákat, hogy külső tárolás és elemzés céljából továbbíthatók legyenek az alkalmazásból. Egyes eszközök konfigurációs fájlokkal vagy felhasználói felületi eszközzel hajthatnak végre konfigurációt az alkalmazáson kívül.

Ez a szakasz az System.Net metrikák gyűjtésének és megtekintésének különböző módszereit mutatja be.

Példaalkalmazás

Az oktatóanyag kedvéért hozzon létre egy egyszerű alkalmazást, amely HTTP-kéréseket küld a különböző végpontokra párhuzamosan.

dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics

Cserélje le a következő mintakód tartalmát Program.cs :

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)];
        byte[] bytes = await client.GetByteArrayAsync(uri, ct);
        await Console.Out.WriteLineAsync($"{uri} - received {bytes.Length} bytes.");
    });
}

Metrikák megtekintése dotnet-counters használatával

dotnet-counters platformfüggetlen teljesítménymonitorozási eszköz az alkalmi állapotmonitorozáshoz és az első szintű teljesítményvizsgálathoz.

dotnet tool install --global dotnet-counters

Ha .NET 8+ folyamaton fut, engedélyezi az argumentum által --counters meghatározott eszközöket, dotnet-counters és megjeleníti a méréseket. Folyamatosan frissíti a konzolt a legújabb számokkal:

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

Metrikák megtekintése a Grafana-ban OpenTelemetry és Prometheus használatával

Áttekintés

OpenTelemetria:

  • A Cloud Native Computing Foundation által támogatott, szállítósemleges, nyílt forráskódú projekt.
  • Szabványosítja a natív felhőbeli szoftverek telemetriájának generálását és gyűjtését.
  • A .NET-tel együttműködik a .NET metrika API-kkal.
  • Az Azure Monitor és számos APM-gyártó támogatja.

Ez az oktatóanyag az OSS Prometheus - és Grafana-projekteket használó OpenTelemetry-metrikákhoz elérhető integrációk egyikét mutatja be. A metrikák adatfolyama a következő lépésekből áll:

  1. A .NET metrika API-k rögzítik a méréseket a példaalkalmazásból.

  2. Az alkalmazásban futó OpenTelemetry-kódtár összesíti a méréseket.

  3. A Prometheus-exportőr kódtára elérhetővé teszi az összesített adatokat EGY HTTP-metrikák végponton keresztül. Az OpenTelemetria az "exportőr" azokat a kódtárakat hívja meg, amelyek telemetriát küldenek a szállítóspecifikus háttérrendszereknek.

  4. Prometheus-kiszolgáló:

    • A metrikák végpontjának lekérdezése.
    • Beolvassa az adatokat.
    • Az adatokat egy adatbázisban tárolja a hosszú távú megőrzése érdekében. A Prometheus arra utal, hogy az adatok olvasása és tárolása végpontok kaparásaként.
    • Egy másik gépen is futtatható.
  5. A Grafana-kiszolgáló:

    • Lekérdezi a Prometheusban tárolt adatokat, és megjeleníti azokat egy webes monitorozási irányítópulton.
    • Egy másik gépen is futtatható.

A példaalkalmazás konfigurálása az OpenTelemetry Prometheus-exportőrének használatára

Adjon hozzá egy hivatkozást az OpenTelemetry Prometheus-exportőrre a példaalkalmazáshoz:

dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease

Feljegyzés

Ez az oktatóanyag az OpenTelemetry Prometheus-támogatásának kiadás előtti buildjét használja, amely az írás időpontjában érhető el.

Frissítés Program.cs OpenTelemetria-konfigurációval:

using OpenTelemetry.Metrics;
using OpenTelemetry;
using System.Net;

using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder()
    .AddMeter("System.Net.Http", "System.Net.NameResolution")
    .AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { "http://localhost:9184/" })
    .Build();

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

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

A fenti kód a következőket végzi el:

  • AddMeter("System.Net.Http", "System.Net.NameResolution") Konfigurálja az OpenTelemetryt a beépített System.Net.Http és System.Net.NameResolution a mérőszámok által gyűjtött összes metrikának továbbítására.
  • AddPrometheusHttpListener Az OpenTelemetria konfigurálása a Prometheus metrikáiNAK HTTP-végpontjának a porton 9184való elérhetővé tételéhez.

Feljegyzés

Ez a konfiguráció ASP.NET Core-alkalmazások esetében különbözik, ahol a metrikákat a rendszer ahelyett exportálja OpenTelemetry.Exporter.Prometheus.AspNetCoreHttpListener. Tekintse meg a kapcsolódó ASP.NET Core-példát.

Futtassa az alkalmazást, és hagyja futni, hogy a mérések összegyűjthetők legyenek:

dotnet run

A Prometheus beállítása és konfigurálása

A Prometheus-kiszolgáló beállításához és működésének ellenőrzéséhez kövesse a Prometheus első lépéseit .

Módosítsa a prometheus.yml konfigurációs fájlt, hogy a Prometheus lekaparja a példaalkalmazás által feltárt metrikák végpontját. Adja hozzá a következő kiemelt szöveget a scrape_configs szakaszhoz:

# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]

  - job_name: 'OpenTelemetryTest'
    scrape_interval: 1s # poll very quickly for a more responsive demo
    static_configs:
      - targets: ['localhost:9184']

Prometheus indítása

  1. Töltse be újra a konfigurációt, vagy indítsa újra a Prometheus-kiszolgálót.

  2. Győződjön meg arról, hogy az OpenTelemetryTest up állapotban van a Prometheus webportál Állapotcélok> lapján. Prometheus status

  3. A Prometheus webportál Gráf lapján írja be http a kifejezés szövegmezőbe, és válassza a lehetőséget http_client_active_requests. http_client_active_requests A gráf lapon a Prometheus megjeleníti a http.client.active_requests példaalkalmazás által kibocsátott számláló értékét. Prometheus active requests graph

Metrikák megjelenítése Grafana-irányítópulton

  1. A Grafana telepítéséhez és Prometheus-adatforráshoz való csatlakoztatásához kövesse a szokásos utasításokat .

  2. Hozzon létre egy Grafana-irányítópultot a + felső eszköztár ikonjának kiválasztásával, majd válassza az Irányítópult lehetőséget. A megjelenő irányítópult-szerkesztőben írja be a Http/1.1 Csatlakozás ions megnyitása kifejezést a Cím mezőbe, a PromQL kifejezésmezőbe pedig a következő lekérdezést:

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

Grafana HTTP/1.1 Connections

  1. Kattintson az Alkalmaz gombra az új irányítópult mentéséhez és megtekintéséhez. Megjeleníti a készlet aktív és tétlen HTTP/1.1 kapcsolatainak számát.

Bővítés

A bővítés egyéni címkéket (más néven attribútumokat vagy címkéket) ad hozzá egy metrikához. Ez akkor hasznos, ha egy alkalmazás egyéni kategorizálást szeretne hozzáadni a metrikákkal létrehozott irányítópultokhoz vagy riasztásokhoz. Az http.client.request.duration eszköz a visszahívások regisztrálásával támogatja a bővítést a HttpMetricsEnrichmentContext. Vegye figyelembe, hogy ez egy alacsony szintű API, és mindegyikhez HttpRequestMessagekülön visszahívási regisztrációra van szükség.

A visszahívási regisztráció egyetlen helyen történő végrehajtásának egyszerű módja egy egyéni DelegatingHandler. Ez lehetővé teszi a kérések elfogását és módosítását, mielőtt továbbítaná őket a belső kezelőnek, és elküldené őket a kiszolgálónak:

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);
    }
}

Ha a következővel IHttpClientFactorydolgozik, regisztrálhatja AddHttpMessageHandler a következőt 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");

Feljegyzés

Teljesítménybeli okokból a rendszer csak akkor hívja meg a bővítési visszahívást, ha az http.client.request.duration eszköz engedélyezve van, ami azt jelenti, hogy valaminek kell összegyűjtenie a metrikákat. Ez lehet dotnet-monitorprometheus exportőr, egy MeterListenervagy egy MetricCollector<T>.

IMeterFactory és IHttpClientFactory integráció

A HTTP-metrikákat az elkülönítés és a tesztelhetőség szem előtt tartásával tervezték. Ezeket a szempontokat támogatja az a használata IMeterFactory, amely lehetővé teszi a mérőszámok egyéni Meter példányok általi közzétételét annak érdekében, hogy a mérőszámok el legyenek különítve egymástól. Alapértelmezés szerint az összes metrikát egy globális Meter belső System.Net.Http tár bocsátja ki. Ez a viselkedés felülbírálható egy egyéni IMeterFactory példány SocketsHttpHandler.MeterFactory hozzárendelésével vagy HttpClientHandler.MeterFactory.

Feljegyzés

Ez Meter.Name az System.Net.Http és által kibocsátott HttpClientHandlerSocketsHttpHandlerösszes metrikára igaz.

Microsoft.Extensions.Http A .NET 8+ használata IHttpClientFactory esetén az alapértelmezett IHttpClientFactory implementáció automatikusan kiválasztja a IMeterFactory példánytIServiceCollection, és hozzárendeli a belsőleg létrehozott elsődleges kezelőhöz.

Feljegyzés

A .NET 8-tól kezdve a AddHttpClient metódus automatikusan meghívja AddMetrics a metrikák szolgáltatásainak inicializálását, és regisztrálja az alapértelmezett IMeterFactory implementációt.IServiceCollection Az alapértelmezett IMeterFactory gyorsítótár a példányokat Meter név szerint gyorsítótárazza, ami azt jelenti, hogy a példányonkénti névvel System.Net.HttpIServiceCollectionrendelkező példány Meter lesz.

Metrikák tesztelése

Az alábbi példa bemutatja, hogyan érvényesítheti a beépített metrikákat az egységtesztekben xUnit használatával, IHttpClientFactoryvalamint MetricCollector<T> a Microsoft.Extensions.Diagnostics.Testing NuGet-csomagból:

[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"]);
        });
}

Metrikák és EventCounters

A metrikák funkciógazdagabbak , mint az EventCounters, elsősorban a többdimenziós jellegük miatt. Ez a többdimenziósság lehetővé teszi kifinomult lekérdezések létrehozását olyan eszközökben, mint a Prometheus, és olyan szintű elemzéseket kaphat, amelyek az EventCountersben nem lehetségesek.

A .NET 8-tól azonban csak az összetevők és System.Net.NameResolutions az System.Net.Http összetevők metrikák használatával vannak kialakítva, ami azt jelenti, hogy ha számlálókra van szüksége a verem alacsonyabb szintjeiről, például System.Net.Sockets vagySystem.Net.Security, akkor EventCounterst kell használnia.

Emellett van néhány szemantikai különbség a metrikák és a hozzájuk tartozó EventCounters között. Az EventCounter például a kérelem HttpCompletionOption.ResponseContentReadcurrent-requests törzsének utolsó bájtjának olvasásáig aktívnak tekinti a kérést. A metrikák megfelelője http.client.active_requests nem tartalmazza a válasz törzsének olvasásával töltött időt az aktív kérések számlálásakor.

További metrikákra van szüksége?

Ha javaslatokat tesz a metrikákon keresztül elérhető egyéb hasznos információkra, hozzon létre egy dotnet-/futtatókörnyezeti problémát.