Utilizzo delle metriche OpenCensus

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Questa pagina illustra le nozioni di base sulla creazione di metriche OpenCensus per gli SLI di disponibilità e latenza. Fornisce anche esempi di implementazione di come definire gli SLO utilizzando le metriche di OpenCensus.

Nozioni di base su OpenCensus

OpenCensus è una singola distribuzione open source di librerie, disponibile nella pagina GitHub di OpenCensus, che raccoglie automaticamente tracce e metriche e le invia a qualsiasi backend. OpenCensus può essere usato per strumenti dei tuoi servizi per emettere metriche personalizzate che possono essere importate in Cloud Monitoring. Potrai quindi utilizzarle come SLI.

Per un esempio che utilizza OpenCensus per creare metriche di Monitoring non destinate espressamente a SLI, consulta Metriche personalizzate con OpenCensus.

Metriche

Per raccogliere dati sulle metriche dal tuo servizio utilizzando OpenCensus, devi utilizzare i seguenti costrutti OpenCensus:

  • Measure, che rappresenta il tipo di metrica da registrare, specificato con un nome. Measure può registrare i valori Int64 o Float64.
  • Measurement: che registra un punto dati specifico raccolto e scritto da un Measure per un determinato evento. Ad esempio, un elemento Measurement potrebbe registrare la latenza di una risposta specifica.
  • View, che specifica un'aggregazione applicata a un Measure. OpenCensus supporta i seguenti tipi di aggregazione:
    • Conteggio: un conteggio del numero di punti di misurazione.
    • Distribuzione: la distribuzione degli istogrammi dei punti di misurazione.
    • Somma: una somma dei valori di misurazione.
    • LastValue: ultimo valore registrato dalla misurazione.

Per ulteriori informazioni, consulta Statistiche/metriche di OpenCensus. Tieni presente che OpenCensus si riferisce spesso alle metriche come statistiche.

Strumentazione

Le librerie OpenCensus sono disponibili per diverse lingue. Per informazioni specifiche sullo strumento di emissione del sistema per le metriche, consulta la pagina relativa al supporto delle lingue di OpenCensus. Inoltre, le metriche personalizzate con OpenCensus forniscono esempi per le lingue comunemente utilizzate con Monitoring.

Nel caso di base, procedi nel seguente modo:

  • Fornisci strumenti ai servizi per registrare ed esportare le metriche.
  • Definisci un esportatore per ricevere le metriche.

Per ogni metrica devi definire un Measure per specificare il tipo di valore: Int64 o Float64. Devi inoltre definire e registrare un View per specificare il tipo di aggregazione (conteggio, distribuzione, somma o ultimo valore). Per utilizzare il tipo di aggregazione della distribuzione, devi anche specificare esplicitamente i limiti del bucket dell'istogramma. Inoltre, puoi specificare un nome per la metrica in View

Esportatore

Infine, devi utilizzare un esportatore per raccogliere le metriche e scriverle su Cloud Monitoring o un altro backend. Per informazioni sugli esportatori specifici per lingua disponibili per Monitoring, consulta gli esportatori di OpenCensus.

Puoi anche scrivere il tuo esportatore; per saperne di più, consulta Scrivere un esportatore personalizzato.

Creazione di metriche per gli SLI

L'applicazione deve creare metriche OpenCensus che possono essere utilizzate come SLI in Cloud Monitoring:

  • Per gli SLI di disponibilità sul numero di richieste e di errori, utilizza un Measure con aggregazione del conteggio.
  • Per gli SLI di latenza, utilizza un Measure con aggregazione della distribuzione.

Metriche per gli SLI di disponibilità

Esprimi uno SLI di disponibilità basato sulla richiesta nell'API Cloud Monitoring utilizzando la struttura TimeSeriesRatio per configurare un rapporto di richieste "buone" o "cattive" rispetto alle richieste totali. Questo rapporto viene utilizzato nel campo goodTotalRatio di una struttura RequestBasedSli.

La tua applicazione deve creare metriche OpenCensus che possano essere utilizzate per creare questo rapporto. Nella tua applicazione, devi creare almeno due dei seguenti elementi:

  1. Una metrica che conteggia gli eventi totali; utilizza questa metrica nella metrica totalServiceFilter.

    Puoi creare una metrica OpenCensus di tipo Int64 con aggregazione dei conteggi, in cui registri un valore 1 per ogni richiesta ricevuta.

  2. Una metrica che conteggia gli eventi "non validi" utilizza questa metrica nel rapporto badServiceFilter.

    Puoi creare una metrica OpenCensus di tipo Int64 con aggregazione dei conteggi, in cui registri un valore 1 per ogni errore o richiesta non riuscita.

  3. Una metrica che conteggia gli eventi con stato "buono" e utilizzala nel rapporto goodServiceFilter.

    Puoi creare una metrica OpenCensus di tipo Int64 con aggregazione dei conteggi, in cui registri un valore pari a 1 per ogni risposta riuscita.

Metriche per gli SLI di latenza

Esprimi uno SLI di latenza basato sulla richiesta nell'API Cloud Monitoring utilizzando una struttura DistributionCut. Questa struttura è utilizzata nel campo distributionCut di una struttura RequestBasedSli.

Puoi creare un oggetto Int64 o Float64 Measure con un elemento View utilizzando il tipo di aggregazione della distribuzione. Devi inoltre definire esplicitamente i limiti dei bucket. Ricorda che è fondamentale definire i bucket in un modo che ti permetta di misurare con precisione la percentuale di richieste che rientrano nella soglia desiderata. Per una discussione su questo argomento, consulta Implementazione degli SLO nel Foglio di lavoro di Site Reliability Engineering.

Esempio di implementazione

Questa sezione presenta un esempio che implementa metriche per gli SLI di disponibilità e latenza di base utilizzando OpenCensus in Node.js.

Strumentazione

Per consentire al tuo servizio di emettere metriche utilizzando OpenCensus, procedi come segue:

  1. Includi le librerie necessarie:

    Go

    import (
    	"flag"
    	"fmt"
    	"log"
    	"math/rand"
    	"net/http"
    	"time"
    
    	"contrib.go.opencensus.io/exporter/stackdriver"
    	"go.opencensus.io/stats"
    	"go.opencensus.io/stats/view"
    	"go.opencensus.io/tag"
    )
    

    Node.js

    // opencensus setup
    const {globalStats, MeasureUnit, AggregationType} = require('@opencensus/core');
    const {StackdriverStatsExporter} = require('@opencensus/exporter-stackdriver');

    Python

    from flask import Flask
    from opencensus.ext.prometheus import stats_exporter as prometheus
    from opencensus.stats import aggregation as aggregation_module
    from opencensus.stats import measure as measure_module
    from opencensus.stats import stats as stats_module
    from opencensus.stats import view as view_module
    from opencensus.tags import tag_map as tag_map_module
    
    from prometheus_flask_exporter import PrometheusMetrics
    
  2. Definisci e registra l'esportatore:

    Go

    // Sets up Cloud Monitoring exporter.
    sd, err := stackdriver.NewExporter(stackdriver.Options{
    	ProjectID:         *projectID,
    	MetricPrefix:      "opencensus-demo",
    	ReportingInterval: 60 * time.Second,
    })
    if err != nil {
    	log.Fatalf("Failed to create the Cloud Monitoring exporter: %v", err)
    }
    defer sd.Flush()
    
    sd.StartMetricsExporter()
    defer sd.StopMetricsExporter()

    Node.js

    // Stackdriver export interval is 60 seconds
    const EXPORT_INTERVAL = 60;
    const exporter = new StackdriverStatsExporter({
      projectId: projectId,
      period: EXPORT_INTERVAL * 1000,
    });
    globalStats.registerExporter(exporter);

    Python

    def setup_openCensus_and_prometheus_exporter() -> None:
        stats = stats_module.stats
        view_manager = stats.view_manager
        exporter = prometheus.new_stats_exporter(prometheus.Options(namespace="oc_python"))
        view_manager.register_exporter(exporter)
        register_all_views(view_manager)
  3. Definisci un Measure per ogni metrica:

    Go

    // Sets up metrics.
    var (
    	requestCount       = stats.Int64("oc_request_count", "total request count", "requests")
    	failedRequestCount = stats.Int64("oc_failed_request_count", "count of failed requests", "requests")
    	responseLatency    = stats.Float64("oc_latency_distribution", "distribution of response latencies", "s")
    )
    

    Node.js

    const REQUEST_COUNT = globalStats.createMeasureInt64(
      'request_count',
      MeasureUnit.UNIT,
      'Number of requests to the server'
    );
    const ERROR_COUNT = globalStats.createMeasureInt64(
      'error_count',
      MeasureUnit.UNIT,
      'Number of failed requests to the server'
    );
    const RESPONSE_LATENCY = globalStats.createMeasureInt64(
      'response_latency',
      MeasureUnit.MS,
      'The server response latency in milliseconds'
    );

    Python

    m_request_count = measure_module.MeasureInt(
        "python_request_count", "total requests", "requests"
    )
    m_failed_request_count = measure_module.MeasureInt(
        "python_failed_request_count", "failed requests", "requests"
    )
    m_response_latency = measure_module.MeasureFloat(
        "python_response_latency", "response latency", "s"
    )
  4. Definisci e registra View per ogni Measure con il tipo di aggregazione appropriato e, per la latenza di risposta, i limiti del bucket:

    Go

    // Sets up views.
    var (
    	requestCountView = &view.View{
    		Name:        "oc_request_count",
    		Measure:     requestCount,
    		Description: "total request count",
    		Aggregation: view.Count(),
    	}
    	failedRequestCountView = &view.View{
    		Name:        "oc_failed_request_count",
    		Measure:     failedRequestCount,
    		Description: "count of failed requests",
    		Aggregation: view.Count(),
    	}
    	responseLatencyView = &view.View{
    		Name:        "oc_response_latency",
    		Measure:     responseLatency,
    		Description: "The distribution of the latencies",
    		// Bucket definitions must be explicitly specified.
    		Aggregation: view.Distribution(0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
    	}
    )
    
    	// Register the views.
    	if err := view.Register(requestCountView, failedRequestCountView, responseLatencyView); err != nil {
    		log.Fatalf("Failed to register the views: %v", err)
    	}

    Node.js

    const request_count_metric = globalStats.createView(
      'request_count_metric',
      REQUEST_COUNT,
      AggregationType.COUNT
    );
    globalStats.registerView(request_count_metric);
    const error_count_metric = globalStats.createView(
      'error_count_metric',
      ERROR_COUNT,
      AggregationType.COUNT
    );
    globalStats.registerView(error_count_metric);
    const latency_metric = globalStats.createView(
      'response_latency_metric',
      RESPONSE_LATENCY,
      AggregationType.DISTRIBUTION,
      [],
      'Server response latency distribution',
      // Latency in buckets:
      [0, 1000, 2000, 3000, 4000, 5000, 10000]
    );
    globalStats.registerView(latency_metric);

    Python

    # set up views
    latency_view = view_module.View(
        "python_response_latency",
        "The distribution of the latencies",
        [],
        m_response_latency,
        aggregation_module.DistributionAggregation(
            [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000]
        ),
    )
    
    request_count_view = view_module.View(
        "python_request_count",
        "total requests",
        [],
        m_request_count,
        aggregation_module.CountAggregation(),
    )
    
    failed_request_count_view = view_module.View(
        "python_failed_request_count",
        "failed requests",
        [],
        m_failed_request_count,
        aggregation_module.CountAggregation(),
    )
    
    # register views
    def register_all_views(view_manager: stats_module.stats.view_manager) -> None:
        view_manager.register_view(latency_view)
        view_manager.register_view(request_count_view)
        view_manager.register_view(failed_request_count_view)
  5. Registra i valori delle metriche Numero richiesta e Numero errore:

    Go

    // Counts the request.
    stats.Record(ctx, requestCount.M(1))
    
    // Randomly fails 10% of the time.
    if rand.Intn(100) >= 90 {
    	// Counts the error.
    	stats.Record(ctx, failedRequestCount.M(1))

    Node.js

    // record a request count for every request
    globalStats.record([
      {
        measure: REQUEST_COUNT,
        value: 1,
      },
    ]);
    
    // randomly throw an error 10% of the time
    const randomValue = Math.floor(Math.random() * 9 + 1);
    if (randomValue === 1) {
      // Record a failed request.
      globalStats.record([
        {
          measure: ERROR_COUNT,
          value: 1,
        },
      ]);

    Python

    mmap = stats_recorder.new_measurement_map()
    # count request
    mmap.measure_int_put(m_request_count, 1)
    # fail 10% of the time
    if random.randint(0, 100) > 90:
        mmap.measure_int_put(m_failed_request_count, 1)
        tmap = tag_map_module.TagMap()
        mmap.record(tmap)
        return ("error!", 500)
  6. Registra i valori di latenza:

    Go

    requestReceived := time.Now()
    // Records latency for failure OR success.
    defer func() {
    	stats.Record(ctx, responseLatency.M(time.Since(requestReceived).Seconds()))
    }()

    Node.js

    globalStats.record([
      {
        measure: RESPONSE_LATENCY,
        value: stopwatch.elapsedMilliseconds,
      },
    ]);

    Python

    start_time = time.perf_counter()
    mmap = stats_recorder.new_measurement_map()
    if random.randint(0, 100) > 90:
        response_latency = time.perf_counter() - start_time
        mmap.measure_float_put(m_response_latency, response_latency)
        tmap = tag_map_module.TagMap()
        mmap.record(tmap)

Metriche importate

Quando le metriche vengono esportate in Cloud Monitoring, vengono visualizzate come tipi di metriche con un prefisso che indica che hanno avuto origine da OpenCensus. Ad esempio, il nome di ogni OpenCensus View nell'implementazione di Node.js è mappato in questo modo:

  • request_count_sli diventa custom.googleapis.com/opencensus/request_count_sli.
  • error_count_sli diventa custom.googleapis.com/opencensus/error_count_sli.
  • response_latency_sli diventa custom.googleapis.com/opencensus/response_latency_sli.

Una volta che il servizio è in esecuzione, puoi confermare che le metriche siano importate in Monitoring cercandole in Metrics Explorer.

SLI di disponibilità

In Cloud Monitoring è possibile esprimere uno SLI di disponibilità basato su richiesta utilizzando una struttura TimeSeriesRatio. L'esempio seguente mostra uno SLO che utilizza le metriche OpenCensus importate e prevede che il servizio abbia una disponibilità del 98%, calcolata dal rapporto tra error_count_sli e request_count_sli in un periodo continuativo di 28 giorni:

{
  "serviceLevelIndicator": {
    "requestBased": {
      "goodTotalRatio": {
        "totalServiceFilter":
          "metric.type=\"custom.googleapis.com/opencensus/request_count_sli\",
       "badServiceFilter":
          "metric.type=\"custom.googleapis.com/opencensus/error_count_sli\"
      }
    }
  },
  "goal": 0.98,
  "rollingPeriod": "2419200s",
  "displayName": "98% Availability, rolling 28 days"
}

SLI di latenza

In Cloud Monitoring è possibile esprimere uno SLI di latenza basato sulla richiesta utilizzando una struttura DistributionCut. L'esempio seguente mostra uno SLO che utilizza la metrica di latenza OpenCensus importata e si aspetta che il 98% delle richieste venga completato in meno di 1000 ms in una finestra temporale continua di un giorno:

{
  "serviceLevelIndicator": {
    "requestBased": {
      "distributionCut": {
        "distributionFilter":
          "metric.type=\"custom.googleapis.com/opencensus/response_latency_sli\",
        "range": {
          "min": 0,
          "max": 1000
        }
      }
    }
  },
  "goal": 0.98,
  "rollingPeriod": "86400s",
  "displayName": "98% requests under 1000 ms"
}