Metryki sieci na platformie .NET
Metryki to pomiary liczbowe zgłaszane w czasie. Są one zwykle używane do monitorowania kondycji aplikacji i generowania alertów.
Począwszy od platformy .NET 8, składniki System.Net.Http
i System.Net.NameResolution
są instrumentowane do publikowania metryk przy użyciu polecenia . Nowy interfejs API System.Diagnostics.Metrics platformy NET.
Te metryki zostały zaprojektowane we współpracy z usługą OpenTelemetry , aby upewnić się, że są one zgodne ze standardem i działają dobrze z popularnymi narzędziami, takimi jak Prometheus i Grafana.
Są one również wielowymiarowe, co oznacza, że miary są skojarzone z parami klucz-wartość nazywanymi tagami (atrybutami lub etykietami), które umożliwiają kategoryzowanie danych na potrzeby analizy.
Napiwek
Aby uzyskać kompleksową listę wszystkich wbudowanych instrumentów wraz z ich atrybutami, zobacz System.Net metryki.
Zbieranie metryk System.Net
Istnieją dwie części używania metryk w aplikacji platformy .NET:
- Instrumentacja: Kod w bibliotekach platformy .NET wykonuje pomiary i kojarzy te miary z nazwą metryki. Platforma .NET i ASP.NET Core zawierają wiele wbudowanych metryk.
- Kolekcja: aplikacja platformy .NET konfiguruje nazwane metryki do przesyłania z aplikacji na potrzeby magazynu zewnętrznego i analizy. Niektóre narzędzia mogą wykonywać konfigurację poza aplikacją przy użyciu plików konfiguracji lub narzędzia interfejsu użytkownika.
W tej sekcji przedstawiono różne metody zbierania i wyświetlania System.Net metryk.
Przykładowa aplikacja
Na potrzeby tego samouczka utwórz prostą aplikację, która równolegle wysyła żądania HTTP do różnych punktów końcowych.
dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics
Zastąp zawartość Program.cs
następującym przykładowym kodem:
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.");
});
}
Wyświetlanie metryk za pomocą liczników dotnet-counter
dotnet-counters
to międzyplatformowe narzędzie do monitorowania wydajności na potrzeby monitorowania kondycji ad hoc i badania wydajności pierwszego poziomu.
dotnet tool install --global dotnet-counters
W przypadku uruchamiania względem procesu dotnet-counters
.NET 8+ włącza instrumenty zdefiniowane przez --counters
argument i wyświetla pomiary. Stale odświeża konsolę przy użyciu najnowszych numerów:
dotnet-counters monitor --counters System.Net.Http,System.Net.NameResolution -n HelloBuiltinMetrics
Wyświetlanie metryk w narzędziu Grafana przy użyciu rozwiązań OpenTelemetry i Prometheus
Omówienie
- Jest neutralnym dla dostawcy projektem open source obsługiwanym przez Cloud Native Computing Foundation.
- Standaryzacja generowania i zbierania danych telemetrycznych dla oprogramowania natywnego dla chmury.
- Współpracuje z platformą .NET przy użyciu interfejsów API metryk platformy .NET.
- Jest zatwierdzony przez usługę Azure Monitor i wielu dostawców APM.
W tym samouczku przedstawiono jedną z integracji dostępnych dla metryk OpenTelemetry przy użyciu projektów Prometheus i Grafana systemu operacyjnego. Przepływ danych metryk składa się z następujących kroków:
Interfejsy API metryk platformy .NET rejestrują pomiary z przykładowej aplikacji.
Biblioteka OpenTelemetry uruchomiona w aplikacji agreguje miary.
Biblioteka eksportera Prometheus udostępnia zagregowane dane za pośrednictwem punktu końcowego metryk HTTP. Funkcja "Eksporter" wywołuje biblioteki, które przesyłają dane telemetryczne do zapleczy specyficznych dla dostawcy.
Serwer Prometheus:
- Sonduje punkt końcowy metryk.
- Odczytuje dane.
- Przechowuje dane w bazie danych pod kątem trwałości długoterminowej. Prometheus odnosi się do odczytywania i przechowywania danych jako złomowania punktu końcowego.
- Można uruchomić na innej maszynie.
Serwer Grafana:
- Wykonuje zapytanie dotyczące danych przechowywanych w rozwiązaniu Prometheus i wyświetla je na internetowym pulpicie nawigacyjnym monitorowania.
- Można uruchomić na innej maszynie.
Konfigurowanie przykładowej aplikacji do korzystania z eksportera Prometheus firmy OpenTelemetry
Dodaj odwołanie do eksportera OpenTelemetry Prometheus do przykładowej aplikacji:
dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
Uwaga
W tym samouczku jest używana kompilacja wstępna obsługi rozwiązania Prometheus firmy OpenTelemetry dostępna w momencie pisania tekstu.
Zaktualizuj Program.cs
za pomocą konfiguracji OpenTelemetry:
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.");
});
}
Powyższy kod:
AddMeter("System.Net.Http", "System.Net.NameResolution")
Konfiguruje bibliotekę OpenTelemetry w celu przesyłania wszystkich metryk zebranych przez wbudowaneSystem.Net.Http
iSystem.Net.NameResolution
mierniki.AddPrometheusHttpListener
Konfiguruje bibliotekę OpenTelemetry w celu uwidocznienia punktu końcowego HTTP metryk rozwiązania Prometheus na porcie9184
.
Uwaga
Ta konfiguracja różni się w przypadku aplikacji ASP.NET Core, w których metryki są eksportowane za pomocą OpenTelemetry.Exporter.Prometheus.AspNetCore
polecenia HttpListener
zamiast . Zobacz powiązany przykład ASP.NET Core.
Uruchom aplikację i pozostaw ją uruchomioną, aby można było zbierać pomiary:
dotnet run
Konfigurowanie i konfigurowanie rozwiązania Prometheus
Wykonaj pierwsze kroki rozwiązania Prometheus, aby skonfigurować serwer Prometheus i upewnij się, że działa.
Zmodyfikuj plik konfiguracji prometheus.yml , tak aby rozwiązanie Prometheus zeskrobało punkt końcowy metryk, na który uwidacznia przykładowa aplikacja. Dodaj następujący wyróżniony tekst w scrape_configs
sekcji:
# 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']
Rozpocznij prometheus
Załaduj ponownie konfigurację lub uruchom ponownie serwer Prometheus.
Upewnij się, że plik OpenTelemetryTest jest w stanie UP na stronie Cele stanu>w portalu internetowym Prometheus.
Na stronie Graf portalu internetowego Prometheus wprowadź
http
w polu tekstowym wyrażenie i wybierz pozycjęhttp_client_active_requests
. Na karcie grafu prometheus pokazuje wartośćhttp.client.active_requests
licznika emitowanego przez przykładowej aplikacji.
Wyświetlanie metryk na pulpicie nawigacyjnym narzędzia Grafana
Postępuj zgodnie ze standardowymi instrukcjami , aby zainstalować aplikację Grafana i połączyć ją ze źródłem danych Prometheus.
Utwórz pulpit nawigacyjny narzędzia Grafana, wybierając ikonę + na górnym pasku narzędzi, a następnie wybierając pozycję Pulpit nawigacyjny. W wyświetlonym edytorze pulpitu nawigacyjnego wprowadź ciąg Otwórz Połączenie ions HTTP/1.1 w polu Tytuł i następujące zapytanie w polu Wyrażenia PromQL:
sum by(http_connection_state) (http_client_open_connections{network_protocol_version="1.1"})
- Wybierz pozycję Zastosuj , aby zapisać i wyświetlić nowy pulpit nawigacyjny. Wyświetla liczbę aktywnych i bezczynnych połączeń HTTP/1.1 w puli.
Wzbogacenie
Wzbogacanie to dodawanie tagów niestandardowych (atrybutów lub etykiet) do metryki. Jest to przydatne, jeśli aplikacja chce dodać niestandardową kategoryzację do pulpitów nawigacyjnych lub alertów utworzonych za pomocą metryk.
http.client.request.duration
Instrument obsługuje wzbogacanie przez zarejestrowanie wywołań zwrotnych w obiekcie HttpMetricsEnrichmentContext.
Należy pamiętać, że jest to interfejs API niskiego poziomu i wymagana jest oddzielna rejestracja wywołania zwrotnego dla każdego HttpRequestMessage
elementu .
Prostym sposobem przeprowadzenia rejestracji wywołania zwrotnego w jednym miejscu jest zaimplementowanie niestandardowego DelegatingHandlerobiektu . Umożliwi to przechwycenie i zmodyfikowanie żądań przed przekazaniem ich do programu obsługi wewnętrznej i wysłaniem ich do serwera:
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);
}
}
Jeśli pracujesz z usługą IHttpClientFactory
, możesz użyć AddHttpMessageHandler polecenia , aby zarejestrować element 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");
Uwaga
Ze względu na wydajność wywołanie zwrotne wzbogacania jest wywoływane tylko wtedy, gdy http.client.request.duration
instrument jest włączony, co oznacza, że coś powinno zbierać metryki.
Może to być dotnet-monitor
, eksporter Prometheus, MeterListener
, lub MetricCollector<T>
.
IMeterFactory
i IHttpClientFactory
integracja
Metryki HTTP zostały zaprojektowane z uwzględnieniem izolacji i możliwości testowania. Te aspekty są obsługiwane przez użycie klasy IMeterFactory, co umożliwia publikowanie metryk przez wystąpienie niestandardowe Meter w celu zachowania izolacji mierników od siebie.
Domyślnie wszystkie metryki są emitowane przez globalny Meter element wewnętrzny do System.Net.Http
biblioteki. To zachowanie może zostać zastąpione przez przypisanie wystąpienia niestandardowego IMeterFactory do SocketsHttpHandler.MeterFactory lub HttpClientHandler.MeterFactory.
Uwaga
Parametr Meter.Name dotyczy System.Net.Http
wszystkich metryk emitowanych przez HttpClientHandler
metryki i SocketsHttpHandler
.
Podczas pracy z platformą Microsoft.Extensions.Http
IHttpClientFactory
.NET 8 lub nowszym domyślna IHttpClientFactory
implementacja automatycznie wybiera IMeterFactory
wystąpienie zarejestrowane w IServiceCollection obiekcie i przypisuje je do podstawowej procedury obsługi, która tworzy wewnętrznie.
Uwaga
Począwszy od platformy .NET 8, AddHttpClient metoda automatycznie wywołuje AddMetrics metodę w celu zainicjowania usług metryk i zarejestrowania domyślnej IMeterFactory implementacji za pomocą polecenia IServiceCollection. Domyślne IMeterFactory buforuje Meter wystąpienia według nazwy, co oznacza, że będzie jeden Meter z nazwą System.Net.Http
na IServiceCollection.
Metryki testów
W poniższym przykładzie pokazano, jak zweryfikować wbudowane metryki w testach jednostkowych przy użyciu narzędzia xUnit, IHttpClientFactory
i MetricCollector<T>
z Microsoft.Extensions.Diagnostics.Testing
pakietu NuGet:
[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"]);
});
}
Metryki a EventCounters
Metryki są bardziej bogate w funkcje niż EventCounters, zwłaszcza ze względu na ich wielowymiarowy charakter. Ta wielowymiarowość umożliwia tworzenie zaawansowanych zapytań w narzędziach, takich jak Prometheus, i uzyskiwanie szczegółowych informacji na poziomie, który nie jest możliwy w przypadku usługi EventCounters.
Niemniej jednak od platformy .NET 8 tylko System.Net.Http
składniki i System.Net.NameResolutions
są instrumentowane przy użyciu metryk, co oznacza, że jeśli potrzebujesz liczników z niższych poziomów stosu, takich jak System.Net.Sockets
lub System.Net.Security
, należy użyć funkcji EventCounters.
Ponadto istnieją pewne semantyczne różnice między metrykami a ich pasującymi elementami EventCounters.
Na przykład w przypadku korzystania z elementu HttpCompletionOption.ResponseContentRead
element current-requests
EventCounter uznaje żądanie za aktywne do momentu odczytania ostatniego bajtu treści żądania.
Jego odpowiednik http.client.active_requests
metryk nie zawiera czasu spędzonego na odczytywaniu treści odpowiedzi podczas liczenia aktywnych żądań.
Potrzebujesz więcej metryk?
Jeśli masz sugestie dotyczące innych przydatnych informacji, które mogą być uwidocznione za pośrednictwem metryk, utwórz problem z dotnet/runtime.