Utiliser les métriques OpenCensus

Cette page présente les principes de base de la création de métriques OpenCensus pour les SLI de disponibilité et de latence. Elle fournit également des exemples de mise en œuvre pour définir des SLO à l'aide de métriques OpenCensus.

Principes de base d'OpenCensus

OpenCensus est un service de distribution Open Source unique de bibliothèques, disponible sur la page GitHub OpenCensus, qui collecte automatiquement les traces et les métriques, et les envoie. à un backend. OpenCensus peut être utilisé pour instrumenter vos services afin d'émettre des métriques personnalisées pouvant être ingérées dans Cloud Monitoring. Vous pouvez ensuite utiliser ces métriques en tant que SLI.

Pour obtenir un exemple d'utilisation d'OpenCensus pour créer des métriques Monitoring qui ne sont pas spécifiquement conçues en tant que SLI, consultez la page Métriques personnalisées avec OpenCensus.

Métriques

Pour collecter des données de métriques à partir de votre service à l'aide d'OpenCensus, vous devez utiliser les constructions OpenCensus suivantes:

  • Measure, qui représente le type de métrique à enregistrer, spécifié avec un nom de métrique. Une Measure peut enregistrer des valeurs Int64 ou Float64.
  • Measurement : enregistre un point de données spécifique collecté et écrit par une Measure pour un événement particulier. Par exemple, un type Measurement peut enregistrer la latence d'une réponse spécifique.
  • View, qui spécifie une agrégation appliquée à une Measure. OpenCensus est compatible avec les types d'agrégation suivants :
    • Nombre: décompte du nombre de points de mesure.
    • Distribution: histogramme des points de mesure.
    • Somme: somme des valeurs de la mesure.
    • LastValue: dernière valeur enregistrée par la mesure.

Pour en savoir plus, consultez la page Statistiques/métriques OpenCensus. Notez qu'OpenCensus emploie souvent statistiques pour faire référence aux métriques.

Instrumentation

Les bibliothèques OpenCensus sont disponibles pour plusieurs langages. Pour plus d'informations par langage spécifique sur l'instrumentation du service pour émettre des métriques, consultez la page Langages compatibles OpenCensus. De plus, la section Métriques personnalisées avec OpenCensus fournit des exemples pour les langages couramment utilisés avec Monitoring.

Dans le cas de base, vous devez effectuer les opérations suivantes:

  • Instrumentez votre service pour enregistrer et exporter des métriques.
  • Définissez un exportateur pour recevoir les métriques.

Pour chaque métrique, vous devez définir un Measure pour spécifier le type de valeur : Int64 ou Float64. Vous devez également définir et enregistrer View pour spécifier le type d'agrégation (nombre, distribution, somme ou dernière valeur). Pour utiliser le type d'agrégation de distribution, vous devez également spécifier explicitement les limites des buckets d'histogramme. Vous devez également spécifier le nom de la métrique dans View.

Exportateur

Enfin, vous devez utiliser un exportateur pour collecter les métriques et les écrire dans Cloud Monitoring ou un autre backend. Pour plus d'informations sur les exportateurs par langages spécifiques disponibles pour Monitoring, consultez la page Exportateurs d'OpenCensus.

Vous pouvez également écrire votre propre exportateur. Pour en savoir plus, consultez la page Écrire un exportateur personnalisé.

Créer des métriques pour les SLI

Votre application doit créer des métriques OpenCensus pouvant être utilisées comme SLI dans Cloud Monitoring:

  • Pour les SLI de disponibilité sur le nombre de requêtes et d'erreurs, utilisez une Measure avec une agrégation de décompte.
  • Pour les SLI de latence, utilisez un Measure avec une agrégation de distribution.

Métriques pour les SLI de disponibilité

Vous pouvez exprimer un SLI de disponibilité basé sur les requêtes dans l'API Cloud Monitoring à l'aide de la structure TimeSeriesRatio pour définir un ratio de "bonnes" ou "bad" requêtes par rapport au nombre total de requêtes. Ce ratio est utilisé dans le champ goodTotalRatio d'une structure RequestBasedSli.

Votre application doit créer des métriques OpenCensus pouvant être utilisées pour créer ce ratio. Dans votre application, vous devez créer au moins deux des éléments suivants:

  1. une métrique qui comptabilise le nombre total d'événements ; Utilisez cette métrique dans le totalServiceFilter du ratio.

    Vous pouvez créer une métrique OpenCensus de type Int64 avec l'agrégation de décompte, où vous enregistrez une valeur de 1 pour chaque requête reçue.

  2. Métrique qui compte les événements "bad", utilisez cette métrique dans le badServiceFilter du ratio.

    Vous pouvez créer une métrique OpenCensus de type Int64 avec l'agrégation de décompte, où vous enregistrez une valeur de 1 pour chaque erreur ou requête ayant échoué.

  3. Métrique qui comptabilise les événements "satisfaisants", utilisez cette métrique dans le goodServiceFilter du ratio.

    Vous pouvez créer une métrique OpenCensus de type Int64 avec l'agrégation de décompte, où vous enregistrez une valeur de 1 pour chaque réponse réussie.

Métriques pour les SLI de latence

Vous pouvez exprimer un SLI de latence basé sur les requêtes dans l'API Cloud Monitoring à l'aide d'une structure DistributionCut. Cette structure est utilisée dans le champ distributionCut d'une structure RequestBasedSli.

Vous pouvez créer une Measure Int64 ou Float64 avec une View en utilisant le type d'agrégation de distribution. Vous devez également définir explicitement les limites de votre bucket. Notez qu'il est essentiel de définir les buckets de manière à pouvoir mesurer précisément le pourcentage de requêtes comprises dans le seuil souhaité. Pour en savoir plus sur ce sujet, consultez la section Mettre en œuvre des SLO du manuel sur l'ingénierie en fiabilité des sites.

Exemple de mise en œuvre

Cette section présente un exemple qui met en œuvre des métriques pour des SLI de disponibilité et de latence de base à l'aide d'OpenCensus dans Node.js.

Instrumentation

Pour instrumenter votre service afin d'émettre des métriques à l'aide d'OpenCensus, procédez comme suit:

  1. Incluez les bibliothèques nécessaires:

    Go

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

    Python

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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. Définissez et enregistrez l'exportateur:

    Go

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    // 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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

    Python

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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. Définissez une Measure pour chaque métrique:

    Go

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    // 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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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. Définissez et enregistrez le View pour chaque Measure avec le type d'agrégation approprié, et pour la latence de réponse, les limites de bucket:

    Go

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    // 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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    # 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. Enregistrez les valeurs pour les métriques du nombre de requêtes et du nombre d'erreurs:

    Go

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    // 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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    // 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

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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. Enregistrez les valeurs de latence :

    Go

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

    Node.js

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

    Python

    Pour vous authentifier auprès de Monitoring, configurez les identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

    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)

Métriques ingérées

Lorsque vos métriques sont exportées vers Cloud Monitoring, elles apparaissent sous la forme de types de métriques avec un préfixe indiquant qu'elles proviennent d'OpenCensus. Par exemple, le nom de chaque View OpenCensus dans l'implémentation Node.js est mappé comme suit:

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

Une fois votre service en cours d'exécution, vous pouvez vérifier que les métriques sont ingérées dans Monitoring en les recherchant dans l'explorateur de métriques.

SLI de disponibilité

Dans Cloud Monitoring, vous exprimez un SLI de disponibilité basé sur les requêtes à l'aide d'une structure TimeSeriesRatio. L'exemple suivant montre un SLO qui utilise les métriques OpenCensus ingérées et s'attend à ce que le service dispose d'une disponibilité de 98 %, d'après le ratio de error_count_sli par rapport à request_count_sli, sur une Période glissante de 28 jours:

{
  "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 de latence

Dans Cloud Monitoring, vous exprimez un SLI de latence basé sur les requêtes à l'aide d'une structure DistributionCut. L'exemple suivant montre un SLO qui utilise la métrique de latence OpenCensus ingérée et s'attend à ce que 98% des requêtes se terminent en moins de 1 000 ms sur une fenêtre glissante d'une journée:

{
  "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"
}