Aracılığıyla paylaş


.NET'te ağ ölçümleri

Ölçümler , zaman içinde bildirilen sayısal ölçümlerdir. Bunlar genellikle bir uygulamanın durumunu izlemek ve uyarılar oluşturmak için kullanılır.

.NET 8'den System.Net.Http başlayarak ve System.Net.NameResolution bileşenleri kullanılarak ölçümleri yayımlamak için izlenir. NET'in yeni System.Diagnostics.Metrics API'si. Bu ölçümler, standartla tutarlı olduklarından ve Prometheusve Grafana gibi popüler araçlarla iyi çalıştıklarından emin olmak için OpenTelemetry ile işbirliği içinde tasarlanmıştır. Ayrıca çok boyutlu olan ölçümler, verilerin analiz için kategorilere ayrılmasına izin veren etiketler (öznitelikler veya etiketler) olarak adlandırılan anahtar-değer çiftleriyle ilişkilendirilir.

İpucu

Tüm yerleşik araçların öznitelikleriyle birlikte kapsamlı bir listesi için bkz . System.Net ölçümler.

System.Net ölçümleri toplama

.NET uygulamasında ölçümleri kullanmanın iki bölümü vardır:

  • İzleme: .NET kitaplıklarındaki kod ölçümler alır ve bu ölçümleri bir ölçüm adıyla ilişkilendirir. .NET ve ASP.NET Core birçok yerleşik ölçüm içerir.
  • Koleksiyon: Bir .NET uygulaması, adlandırılmış ölçümleri dış depolama ve analiz için uygulamadan iletilecek şekilde yapılandırıyor. Bazı araçlar yapılandırma dosyalarını veya kullanıcı arabirimi aracını kullanarak uygulamanın dışında yapılandırma gerçekleştirebilir.

Bu bölümde, System.Net ölçümleri toplamak ve görüntülemek için çeşitli yöntemler gösterilmektedir.

Örnek uygulama

Bu öğreticinin iyiliği için, çeşitli uç noktalara paralel olarak HTTP istekleri gönderen basit bir uygulama oluşturun.

dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics

öğesinin içeriğini Program.cs aşağıdaki örnek kodla değiştirin:

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

Dotnet-counters ile ölçümleri görüntüleme

dotnet-counters geçici sistem durumu izleme ve birinci düzey performans araştırması için platformlar arası bir performans izleme aracıdır.

dotnet tool install --global dotnet-counters

.NET 8+ işlemine karşı çalışırken bağımsız dotnet-counters değişken tarafından --counters tanımlanan araçları etkinleştirir ve ölçümleri görüntüler. Konsolu sürekli olarak en son sayılarla yeniler:

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

OpenTelemetry ve Prometheus ile Grafana'da ölçümleri görüntüleme

Genel bakış

OpenTelemetry:

Bu öğreticide, OSS Prometheus ve Grafana projelerini kullanarak OpenTelemetry ölçümleri için kullanılabilen tümleştirmelerden biri gösterilmektedir. Ölçüm veri akışı aşağıdaki adımlardan oluşur:

  1. .NET ölçüm API'leri örnek uygulamadaki ölçümleri kaydeder.

  2. Uygulamada çalıştırılan OpenTelemetry kitaplığı ölçümleri toplar.

  3. Prometheus dışarı aktarma kitaplığı, toplanan verileri bir HTTP ölçüm uç noktası aracılığıyla kullanılabilir hale getirir. 'Exporter', OpenTelemetry'nin telemetri verilerini satıcıya özgü arka uçlara ileten kitaplıkları çağıran şeydir.

  4. Prometheus sunucusu:

    • Ölçüm uç noktasını yoklar.
    • Verileri okur.
    • Verileri uzun süreli kalıcılık için bir veritabanında depolar. Prometheus, verileri okuma ve depolamayı bir uç noktayı kazıma olarak ifade eder.
    • Farklı bir makinede çalıştırılabilir.
  5. Grafana sunucusu:

    • Prometheus'ta depolanan verileri sorgular ve web tabanlı bir izleme panosunda görüntüler.
    • Farklı bir makinede çalıştırılabilir.

Örnek uygulamayı OpenTelemetry'nin Prometheus dışarı aktarmasını kullanacak şekilde yapılandırma

Örnek uygulamaya OpenTelemetry Prometheus verenine bir başvuru ekleyin:

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

Not

Bu öğreticide, yazma sırasında sağlanan OpenTelemetry Prometheus desteğinin yayın öncesi derlemesi kullanılmaktadır.

OpenTelemetry yapılandırmasıyla güncelleştirme Program.cs :

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

Önceki kodda:

  • AddMeter("System.Net.Http", "System.Net.NameResolution")Yerleşik ve System.Net.NameResolution ölçümler tarafından toplanan tüm ölçümleri iletmek için OpenTelemetry'yi System.Net.Http yapılandırıyor.
  • AddPrometheusHttpListener , Bağlantı noktasında 9184Prometheus'un ölçümleri HTTP uç noktasını kullanıma sunacak OpenTelemetry'yi yapılandırıyor.

Not

Bu yapılandırma, ölçümlerin HttpListeneryerine ile OpenTelemetry.Exporter.Prometheus.AspNetCore dışarı aktarıldığı ASP.NET Core uygulamaları için farklılık gösterir. İlgili ASP.NET Core örneğine bakın.

Ölçümlerin toplanabilmesi için uygulamayı çalıştırın ve çalışır durumda bırakın:

dotnet run

Prometheus'ı ayarlama ve yapılandırma

Prometheus sunucusunu ayarlamak için Prometheus ilk adımlarını izleyin ve çalıştığını doğrulayın.

prometheus.yml yapılandırma dosyasını, Prometheus'un örnek uygulamanın sergilediğini ölçümler uç noktasını kazıması için değiştirin. Bölümüne aşağıdaki vurgulanmış metni scrape_configs ekleyin:

# 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'ı başlatma

  1. Yapılandırmayı yeniden yükleyin veya Prometheus sunucusunu yeniden başlatın.

  2. OpenTelemetryTest'in Prometheus web portalının Durum>Hedefleri sayfasında UP durumunda olduğunu onaylayın. Prometheus status

  3. Prometheus web portalının Graf sayfasında, ifade metin kutusuna yazın http ve öğesini seçin http_client_active_requests. http_client_active_requests Grafik sekmesinde, Prometheus örnek uygulama tarafından yayılan sayacın değerini http.client.active_requests gösterir. Prometheus active requests graph

Grafana panosunda ölçümleri gösterme

  1. Grafana'yı yüklemek ve prometheus veri kaynağına bağlamak için standart yönergeleri izleyin.

  2. Üst araç çubuğundaki simgeyi + ve ardından Pano'yu seçerek grafana panosu oluşturun. Görüntülenen pano düzenleyicisinde Başlık kutusuna HTTP/1.1 Bağlan ions'ı aç ve PromQL ifade alanına aşağıdaki sorguyu girin:

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

Grafana HTTP/1.1 Connections

  1. Yeni panoyu kaydetmek ve görüntülemek için Uygula'yı seçin. Havuzdaki etkin ve boş http/1.1 bağlantılarının sayısını görüntüler.

Zenginleştirme

Zenginleştirme , bir ölçüme özel etiketlerin (yani özniteliklerin veya etiketlerin) eklenmesidir. Bu, bir uygulama ölçümlerle oluşturulmuş panolara veya uyarılara özel bir kategori eklemek istediğinde kullanışlıdır. Araç, http.client.request.duration geri çağırmaları ile kaydederek zenginleştirmeyi HttpMetricsEnrichmentContextdestekler. Bunun düşük düzeyli bir API olduğunu ve her HttpRequestMessageiçin ayrı bir geri çağırma kaydı gerektiğini unutmayın.

Geri çağırma kaydını tek bir yerde yapmanın basit bir yolu özel DelegatingHandlerbir uygulamaktır. Bu, istekleri iç işleyiciye iletilmeden ve sunucuya gönderilmeden önce kesmenize ve değiştirmenize olanak sağlar:

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

ile IHttpClientFactoryçalışıyorsanız, öğesini kaydetmek EnrichmentHandleriçin kullanabilirsinizAddHttpMessageHandler:

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

Not

Performans nedenleriyle, zenginleştirme geri çağırması yalnızca araç etkinleştirildiğinde http.client.request.duration çağrılır; başka bir deyişle ölçümleri bir şeyin toplaması gerekir. dotnet-monitorBu , Prometheus ihracatçısı, veya MeterListenerolabilirMetricCollector<T>.

IMeterFactory ve IHttpClientFactory tümleştirme

HTTP ölçümleri yalıtım ve test edilebilirlik göz önünde bulundurularak tasarlanmıştır. Bu özellikler, Ölçümler'i IMeterFactorybirbirinden yalıtmak için ölçümlerin özel Meter bir örnek tarafından yayımlanmasını sağlayan kullanımıyla desteklenir. Varsayılan olarak, tüm ölçümler genel bir Meter iç tarafından kitaplığa System.Net.Http yayılır. Bu davranış, veya HttpClientHandler.MeterFactoryöğesine özel IMeterFactory bir örnek SocketsHttpHandler.MeterFactory atanarak geçersiz kılınabilir.

Not

, Meter.Name ve SocketsHttpHandlertarafından HttpClientHandler yayılan tüm ölçümlere yöneliktirSystem.Net.Http.

.NET 8+ ile Microsoft.Extensions.Http ve IHttpClientFactory üzerinde çalışırken, varsayılan IHttpClientFactory uygulama içinde kayıtlı IServiceCollection örneği otomatik olarak seçer IMeterFactory ve dahili olarak oluşturduğu birincil işleyiciye atar.

Not

.NET 8'den başlayarak yöntemi, AddHttpClient ölçüm hizmetlerini başlatmak ve varsayılan IMeterFactory uygulamayı ile IServiceCollectionkaydetmek için otomatik olarak öğesini çağırırAddMetrics. VarsayılanIMeterFactory, örnekleri ada göre önbelleğe Meter alır; yani her IServiceCollectionbiri adına sahip bir Meter örnek System.Net.Http olacaktır.

Test ölçümleri

Aşağıdaki örnekte, xUnit, IHttpClientFactoryve MetricCollector<T> kullanarak NuGet paketinden birim testlerinde yerleşik ölçümlerin nasıl doğrulanması Microsoft.Extensions.Diagnostics.Testing gösterilmektedir:

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

Ölçümler ile EventCounters karşılaştırması

Ölçümler , özellikle çok boyutlu doğası nedeniyle EventCounters'dan daha zengin özelliklere sahiptir. Bu çok boyutluluk, Prometheus gibi araçlarda karmaşık sorgular oluşturmanıza ve EventCounters ile mümkün olmayan bir düzeyde içgörüler elde etmenize olanak tanır.

Bununla birlikte, .NET 8'den itibaren yalnızca System.Net.Http ve System.Net.NameResolutions bileşenleri Ölçümler kullanılarak izlenir; başka bir deyişle, veya System.Net.Securitygibi System.Net.Sockets yığının alt düzeylerinden sayaçlara ihtiyacınız varsa EventCounters kullanmanız gerekir.

Ayrıca Ölçümler ile bunların eşleşen EventCounter'ları arasında bazı semantik farklılıklar vardır. Örneğin, kullanırken HttpCompletionOption.ResponseContentReadEventCounter istek gövdesinin current-requests son baytının okunduğu ana kadar bir isteğin etkin olduğunu düşünür. Ölçümler, http.client.active_requests etkin istekleri sayarken yanıt gövdesini okumak için harcanan zamanı içermez.

Daha fazla ölçüme mi ihtiyacınız var?

Ölçümler aracılığıyla kullanıma sunulacak diğer yararlı bilgiler için önerileriniz varsa bir dotnet/runtime sorunu oluşturun.