Dela via


Självstudie: Mäta prestanda med EventCounters i .NET Core

Den här artikeln gäller för: ✔️ .NET Core 3.0 SDK och senare versioner

I den här självstudien får du lära dig hur en EventCounter kan användas för att mäta prestanda med hög händelsefrekvens. Du kan använda de tillgängliga räknare som publicerats av olika officiella .NET Core-paket, tredjepartsleverantörer eller skapa egna mått för övervakning.

I de här självstudierna får du:

Förutsättningar

Självstudien använder:

Hämta källan

Exempelprogrammet används som grund för övervakning. Exempellagringsplatsen ASP.NET Core är tillgänglig från exempelwebbläsaren. Du laddar ned zip-filen, extraherar den när den har laddats ned och öppnar den i din favorit-IDE. Skapa och kör programmet för att säkerställa att det fungerar korrekt och stoppa sedan programmet.

Implementera en EventSource

För händelser som inträffar med några millisekunders mellanrum vill du att omkostnaderna per händelse ska vara låga (mindre än en millisekunder). Annars blir prestandapåverkan betydande. Att logga en händelse innebär att du kommer att skriva något till disken. Om disken inte är tillräckligt snabb förlorar du händelser. Du behöver en annan lösning än att logga själva händelsen.

När du hanterar ett stort antal händelser är det inte heller användbart att känna till måttet per händelse. För det mesta behöver du bara lite statistik. Så du kan hämta statistiken i själva processen och sedan skriva en händelse då och då för att rapportera statistiken, det är vad EventCounter som kommer att göra.

Nedan visas ett exempel på hur du implementerar en System.Diagnostics.Tracing.EventSource. Skapa en ny fil med namnet MinimalEventCounterSource.cs och använd kodfragmentet som källa:

using System.Diagnostics.Tracing;

[EventSource(Name = "Sample.EventCounter.Minimal")]
public sealed class MinimalEventCounterSource : EventSource
{
    public static readonly MinimalEventCounterSource Log = new MinimalEventCounterSource();

    private EventCounter _requestCounter;

    private MinimalEventCounterSource() =>
        _requestCounter = new EventCounter("request-time", this)
        {
            DisplayName = "Request Processing Time",
            DisplayUnits = "ms"
        };

    public void Request(string url, long elapsedMilliseconds)
    {
        WriteEvent(1, url, elapsedMilliseconds);
        _requestCounter?.WriteMetric(elapsedMilliseconds);
    }

    protected override void Dispose(bool disposing)
    {
        _requestCounter?.Dispose();
        _requestCounter = null;

        base.Dispose(disposing);
    }
}

Raden EventSource.WriteEvent är delen EventSource och är inte en del av EventCounter, den skrevs för att visa att du kan logga ett meddelande tillsammans med händelseräknaren.

Lägga till ett åtgärdsfilter

Exempelkällan är ett ASP.NET Core projekt. Du kan lägga till ett åtgärdsfilter globalt som loggar den totala begärandetiden. Skapa en ny fil med namnet LogRequestTimeFilterAttribute.cs och använd följande kod:

using System.Diagnostics;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.Filters;

namespace DiagnosticScenarios
{
    public class LogRequestTimeFilterAttribute : ActionFilterAttribute
    {
        readonly Stopwatch _stopwatch = new Stopwatch();

        public override void OnActionExecuting(ActionExecutingContext context) => _stopwatch.Start();

        public override void OnActionExecuted(ActionExecutedContext context)
        {
            _stopwatch.Stop();

            MinimalEventCounterSource.Log.Request(
                context.HttpContext.Request.GetDisplayUrl(), _stopwatch.ElapsedMilliseconds);
        }
    }
}

Åtgärdsfiltret startar en Stopwatch när begäran börjar och stoppas när den har slutförts, vilket fångar den förflutna tiden. Totalt antal millisekunder loggas till singleton-instansen MinimalEventCounterSource . För att det här filtret ska tillämpas måste du lägga till det i filtersamlingen. I filen Startup.cs uppdaterar ConfigureServices du metoden i inkludera det här filtret.

public void ConfigureServices(IServiceCollection services) =>
    services.AddControllers(options => options.Filters.Add<LogRequestTimeFilterAttribute>())
            .AddNewtonsoftJson();

Övervaka händelseräknare

Med implementeringen på ett EventSource och det anpassade åtgärdsfiltret skapar och startar du programmet. Du loggade måttet EventCountertill , men om du inte kommer åt statistiken från det är det inte användbart. För att hämta statistiken måste du aktivera EventCounter genom att skapa en timer som utlöses så ofta du vill att händelserna ska aktiveras, samt en lyssnare för att fånga händelserna. För att göra det kan du använda dotnet-counters.

Använd kommandot dotnet-counters ps för att visa en lista över .NET-processer som kan övervakas.

dotnet-counters ps

Med processidentifieraren från kommandots dotnet-counters ps utdata kan du börja övervaka händelseräknaren med följande dotnet-counters monitor kommando:

dotnet-counters monitor --process-id 2196 --counters Sample.EventCounter.Minimal,Microsoft.AspNetCore.Hosting[total-requests,requests-per-second],System.Runtime[cpu-usage]

dotnet-counters monitor När kommandot körs håller du F5 i webbläsaren för att börja utfärda kontinuerliga begäranden till https://localhost:5001/api/values slutpunkten. Efter några sekunders stopp genom att trycka på q

Press p to pause, r to resume, q to quit.
    Status: Running

[Microsoft.AspNetCore.Hosting]
    Request Rate / 1 sec                               9
    Total Requests                                   134
[System.Runtime]
    CPU Usage (%)                                     13
[Sample.EventCounter.Minimal]
    Request Processing Time (ms)                      34.5

Kommandot dotnet-counters monitor är bra för aktiv övervakning. Du kanske dock vill samla in dessa diagnostikmått för efterbearbetning och analys. För det använder du dotnet-counters collect kommandot . Switch-kommandot collect liknar monitor kommandot, men accepterar några ytterligare parametrar. Du kan ange önskat namn och format för utdatafilen. För en JSON-fil med namnet diagnostics.json använder du följande kommando:

dotnet-counters collect --process-id 2196 --format json -o diagnostics.json --counters Sample.EventCounter.Minimal,Microsoft.AspNetCore.Hosting[total-requests,requests-per-second],System.Runtime[cpu-usage]

När kommandot körs håller du F5 i webbläsaren för att börja utfärda kontinuerliga begäranden till https://localhost:5001/api/values slutpunkten. Efter några sekunder stannar du genom att trycka på q. Filen diagnostics.json är skriven. JSON-filen som skrivs är dock inte indragen. för läsbarhet är det indrag här.

{
  "TargetProcess": "DiagnosticScenarios",
  "StartTime": "8/5/2020 3:02:45 PM",
  "Events": [
    {
      "timestamp": "2020-08-05 15:02:47Z",
      "provider": "System.Runtime",
      "name": "CPU Usage (%)",
      "counterType": "Metric",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:47Z",
      "provider": "Microsoft.AspNetCore.Hosting",
      "name": "Request Rate / 1 sec",
      "counterType": "Rate",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:47Z",
      "provider": "Microsoft.AspNetCore.Hosting",
      "name": "Total Requests",
      "counterType": "Metric",
      "value": 134
    },
    {
      "timestamp": "2020-08-05 15:02:47Z",
      "provider": "Sample.EventCounter.Minimal",
      "name": "Request Processing Time (ms)",
      "counterType": "Metric",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:47Z",
      "provider": "System.Runtime",
      "name": "CPU Usage (%)",
      "counterType": "Metric",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:48Z",
      "provider": "Microsoft.AspNetCore.Hosting",
      "name": "Request Rate / 1 sec",
      "counterType": "Rate",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:48Z",
      "provider": "Microsoft.AspNetCore.Hosting",
      "name": "Total Requests",
      "counterType": "Metric",
      "value": 134
    },
    {
      "timestamp": "2020-08-05 15:02:48Z",
      "provider": "Sample.EventCounter.Minimal",
      "name": "Request Processing Time (ms)",
      "counterType": "Metric",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:48Z",
      "provider": "System.Runtime",
      "name": "CPU Usage (%)",
      "counterType": "Metric",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:50Z",
      "provider": "Microsoft.AspNetCore.Hosting",
      "name": "Request Rate / 1 sec",
      "counterType": "Rate",
      "value": 0
    },
    {
      "timestamp": "2020-08-05 15:02:50Z",
      "provider": "Microsoft.AspNetCore.Hosting",
      "name": "Total Requests",
      "counterType": "Metric",
      "value": 134
    },
    {
      "timestamp": "2020-08-05 15:02:50Z",
      "provider": "Sample.EventCounter.Minimal",
      "name": "Request Processing Time (ms)",
      "counterType": "Metric",
      "value": 0
    }
  ]
}

Nästa steg