Bagikan melalui


Metrik jaringan di .NET

Metrik adalah pengukuran numerik yang dilaporkan dari waktu ke waktu. Mereka biasanya digunakan untuk memantau kesehatan aplikasi dan menghasilkan pemberitahuan.

Dimulai dengan .NET 8, System.Net.Http dan System.Net.NameResolution komponen diinstrumentasikan untuk menerbitkan metrik menggunakan . API System.Diagnostics.Metrics baru NET. Metrik ini dirancang bekerja sama dengan OpenTelemetry untuk memastikan metrik tersebut konsisten dengan standar dan bekerja dengan baik dengan alat populer seperti Prometheus dan Grafana. Mereka juga multi-dimensi, yang berarti bahwa pengukuran dikaitkan dengan pasangan kunci-nilai yang disebut tag (alias atribut atau label) yang memungkinkan data dikategorikan untuk analisis.

Tip

Untuk daftar komprehensif semua instrumen bawaan bersama dengan atributnya, lihat metrik System.Net.

Mengumpulkan metrik System.Net

Ada dua bagian untuk menggunakan metrik dalam aplikasi .NET:

  • Instrumentasi: Kode dalam pustaka .NET mengambil pengukuran dan mengaitkan pengukuran ini dengan nama metrik. .NET dan ASP.NET Core mencakup banyak metrik bawaan.
  • Koleksi: Aplikasi .NET mengonfigurasi metrik bernama untuk dikirimkan dari aplikasi untuk penyimpanan dan analisis eksternal. Beberapa alat mungkin melakukan konfigurasi di luar aplikasi menggunakan file konfigurasi atau alat UI.

Bagian ini menunjukkan berbagai metode untuk mengumpulkan dan melihat metrik System.Net.

Contoh aplikasi

Demi tutorial ini, buat aplikasi sederhana yang mengirim permintaan HTTP ke berbagai titik akhir secara paralel.

dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics

Ganti konten Program.cs dengan kode sampel berikut:

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

Melihat metrik dengan penghitung dotnet

dotnet-counters adalah alat pemantauan performa lintas platform untuk pemantauan kesehatan ad-hoc dan investigasi performa tingkat pertama.

dotnet tool install --global dotnet-counters

Saat berjalan terhadap proses .NET 8+, dotnet-counters memungkinkan instrumen yang ditentukan oleh --counters argumen dan menampilkan pengukuran. Konsol ini terus menyegarkan konsol dengan angka terbaru:

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

Melihat metrik di Grafana dengan OpenTelemetry dan Prometheus

Gambaran Umum

OpenTelemetry:

  • Adalah proyek sumber terbuka yang netral vendor yang didukung oleh Cloud Native Computing Foundation.
  • Menstandarkan pembuatan dan pengumpulan telemetri untuk perangkat lunak cloud-native.
  • Bekerja dengan .NET menggunakan API metrik .NET.
  • Didukung oleh Azure Monitor dan banyak vendor APM.

Tutorial ini menunjukkan salah satu integrasi yang tersedia untuk metrik OpenTelemetry menggunakan proyek OSS Prometheus dan Grafana . Aliran data metrik terdiri dari langkah-langkah berikut:

  1. API metrik .NET merekam pengukuran dari aplikasi contoh.

  2. Pustaka OpenTelemetry yang berjalan di aplikasi menggabungkan pengukuran.

  3. Pustaka pengekspor Prometheus membuat data agregat tersedia melalui titik akhir metrik HTTP. 'Pengekspor' adalah apa yang disebut OpenTelemetry pustaka yang mengirimkan telemetri ke backend khusus vendor.

  4. Server Prometheus:

    • Polling titik akhir metrik.
    • Membaca data.
    • Menyimpan data dalam database untuk persistensi jangka panjang. Prometheus mengacu pada membaca dan menyimpan data sebagai mengikis titik akhir.
    • Dapat berjalan pada komputer yang berbeda.
  5. Server Grafana:

    • Mengkueri data yang disimpan di Prometheus dan menampilkannya di dasbor pemantauan berbasis web.
    • Dapat berjalan pada komputer yang berbeda.

Mengonfigurasi contoh aplikasi untuk menggunakan pengekspor Prometheus OpenTelemetry

Tambahkan referensi ke pengekspor OpenTelemetry Prometheus ke aplikasi contoh:

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

Catatan

Tutorial ini menggunakan build pra-rilis dukungan Prometheus OpenTelemetry yang tersedia pada saat penulisan.

Perbarui Program.cs dengan konfigurasi 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.");
    });
}

Dalam kode sebelumnya:

  • AddMeter("System.Net.Http", "System.Net.NameResolution") mengonfigurasi OpenTelemetry untuk mengirimkan semua metrik yang dikumpulkan oleh bawaan System.Net.Http dan System.Net.NameResolution meter.
  • AddPrometheusHttpListener mengonfigurasi OpenTelemetry untuk mengekspos titik akhir HTTP metrik Prometheus pada port 9184.

Catatan

Konfigurasi ini berbeda untuk aplikasi ASP.NET Core, di mana metrik diekspor dengan OpenTelemetry.Exporter.Prometheus.AspNetCore alih-alih HttpListener. Lihat contoh ASP.NET Core terkait.

Jalankan aplikasi dan biarkan berjalan sehingga pengukuran dapat dikumpulkan:

dotnet run

Menyiapkan dan mengonfigurasi Prometheus

Ikuti langkah-langkah pertama Prometheus untuk menyiapkan server Prometheus dan mengonfirmasi bahwa prometheus berfungsi.

Ubah file konfigurasi prometheus.yml sehingga Prometheus mengekstrak titik akhir metrik yang diekspos aplikasi contoh. Tambahkan teks yang disorot berikut ini di bagian scrape_configs :

# 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']

Mulai prometheus

  1. Muat ulang konfigurasi atau mulai ulang server Prometheus.

  2. Konfirmasikan bahwa OpenTelemetryTest berada dalam status UP di halaman Target Status>portal web Prometheus. Prometheus status

  3. Pada halaman Grafik portal web Prometheus, masukkan http dalam kotak teks ekspresi dan pilih http_client_active_requests. http_client_active_requests Di tab grafik, Prometheus menunjukkan nilai http.client.active_requests penghitung yang dipancarkan oleh aplikasi contoh. Prometheus active requests graph

Menampilkan metrik di dasbor Grafana

  1. Ikuti instruksi standar untuk menginstal Grafana dan menyambungkannya ke sumber data Prometheus.

  2. Buat dasbor Grafana dengan memilih + ikon di toolbar atas lalu pilih Dasbor. Di editor dasbor yang muncul, masukkan Buka Koneksi ion HTTP/1.1 di kotak Judul dan kueri berikut di bidang ekspresi PromQL:

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

Grafana HTTP/1.1 Connections

  1. Pilih Terapkan untuk menyimpan dan menampilkan dasbor baru. Ini menampilkan jumlah koneksi HTTP/1.1 aktif vs diam di kumpulan.

Pengayaan

Pengayaan adalah penambahan tag kustom (alias atribut atau label) ke metrik. Ini berguna jika aplikasi ingin menambahkan kategorisasi kustom ke dasbor atau pemberitahuan yang dibangun dengan metrik. Instrumen http.client.request.duration ini mendukung pengayaan dengan mendaftarkan panggilan balik dengan HttpMetricsEnrichmentContext. Perhatikan bahwa ini adalah API tingkat rendah dan pendaftaran panggilan balik terpisah diperlukan untuk setiap HttpRequestMessage.

Cara sederhana untuk melakukan pendaftaran panggilan balik di satu tempat adalah dengan menerapkan kustom DelegatingHandler. Ini akan memungkinkan Anda untuk mencegat dan memodifikasi permintaan sebelum diteruskan ke handler dalam dan dikirim ke 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);
    }
}

Jika Anda bekerja dengan IHttpClientFactory, Anda dapat menggunakan AddHttpMessageHandler untuk mendaftarkan 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");

Catatan

Untuk alasan performa, panggilan balik pengayaan hanya dipanggil ketika http.client.request.duration instrumen diaktifkan, yang berarti bahwa sesuatu harus mengumpulkan metrik. Ini bisa menjadi dotnet-monitor, pengekspor Prometheus, MeterListener, atau MetricCollector<T>.

IMeterFactory dan IHttpClientFactory integrasi

Metrik HTTP dirancang dengan pertimbangkan isolasi dan kemampuan pengujian. Aspek-aspek ini didukung oleh penggunaan IMeterFactory, yang memungkinkan penerbitan metrik oleh instans kustom Meter untuk menjaga Meter terisolasi satu sama lain. Secara default, semua metrik dipancarkan oleh internal global Meter ke System.Net.Http pustaka. Perilaku ini dapat ditimpa dengan menetapkan instans kustom IMeterFactory ke SocketsHttpHandler.MeterFactory atau HttpClientHandler.MeterFactory.

Catatan

Meter.Name adalah System.Net.Http untuk semua metrik yang dipancarkan oleh HttpClientHandler dan SocketsHttpHandler.

Saat bekerja dengan Microsoft.Extensions.Http dan IHttpClientFactory di .NET 8+, implementasi default IHttpClientFactory secara otomatis memilih instans IMeterFactory yang terdaftar di IServiceCollection dan menetapkannya ke handler utama yang dibuatnya secara internal.

Catatan

Dimulai dengan .NET 8, AddHttpClient metode secara otomatis memanggil AddMetrics untuk menginisialisasi layanan metrik dan mendaftarkan implementasi default IMeterFactory dengan IServiceCollection. Instans Meter cache default IMeterFactory berdasarkan nama, yang berarti bahwa akan ada satu Meter dengan nama System.Net.Http per IServiceCollection.

Menguji metrik

Contoh berikut menunjukkan cara memvalidasi metrik bawaan dalam pengujian unit menggunakan xUnit, IHttpClientFactory, dan MetricCollector<T> dari Microsoft.Extensions.Diagnostics.Testing paket 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"]);
        });
}

Metrik vs. EventCounters

Metrik lebih kaya fitur daripada EventCounters, terutama karena sifat multi-dimensinya. Multidimensi ini memungkinkan Anda membuat kueri canggih dalam alat seperti Prometheus dan mendapatkan wawasan tentang tingkat yang tidak dimungkinkan dengan EventCounters.

Namun demikian, pada .NET 8, hanya System.Net.Http komponen dan System.Net.NameResolutions yang diinstrumentasikan menggunakan Metrik, yang berarti bahwa jika Anda memerlukan penghitung dari tingkat tumpukan yang lebih rendah seperti System.Net.Sockets atau System.Net.Security, Anda harus menggunakan EventCounters.

Selain itu, ada beberapa perbedaan semantik antara Metrik dan EventCounters yang cocok. Misalnya, saat menggunakan HttpCompletionOption.ResponseContentRead, current-requests EventCounter menganggap permintaan aktif hingga saat byte terakhir dari isi permintaan telah dibaca. Rekan http.client.active_requests metriknya tidak termasuk waktu yang dihabiskan untuk membaca isi respons saat menghitung permintaan aktif.

Perlu lebih banyak metrik?

Jika Anda memiliki saran untuk informasi berguna lainnya yang dapat diekspos melalui metrik, buat masalah dotnet/runtime.