Back home

Division des limites des journaux, des indicateurs et du traçage

Les indicateurs sont responsables de la découverte des anomalies, le traçage est responsable du rétrécissement du chemin et les journaux sont responsables de la restauration de la scène ; mélanger les trois ne fera qu’augmenter le coût du dépannage.

La première réaction de nombreuses équipes lorsqu’elles tentent de compléter l’observabilité est de « connecter les journaux, les indicateurs et le traçage ».

Cette phrase semble correcte, mais le vrai problème réside dans l’étape suivante : les trois choses sont liées, mais les limites ne sont pas déterminées, donc chaque méthode efface les fesses des deux autres.

Les résultats sont généralement très familiers : les étiquettes des indicateurs explosent, l’échantillonnage du traçage augmente considérablement, le volume des journaux double chaque mois, les alarmes sont toujours inexactes et le dépannage repose toujours sur la détection humaine. Les outils ne manquent pas, mais le système n’est pas vraiment devenu plus observable.

Mon jugement est le suivant : **Les limites des journaux, des indicateurs et du traçage ne doivent pas être tracées par « à quoi ressemblent les données » mais par « quelle décision prendre ensuite ». **

  • L’indicateur répond : si le problème doit être traité immédiatement et si la portée de l’impact est large ;
  • Recherche des réponses : sur quelle section du lien le problème est probablement bloqué ?
  • Le journal répond : Que s’est-il passé exactement dans ce morceau de code dans cette requête.

Les trois sont dans une relation de coûts décisionnels croissants. L’indicateur est le moins cher et adapté à une surveillance continue du marché ; Le traçage est plus coûteux et permet de réduire la portée ; le rondin est le plus lourd et convient à la restauration finale de la scène.

Si le journal est responsable des alarmes, Tracing est responsable de l’audit et les indicateurs sont responsables de chaque utilisateur, chaque commande et chaque dimension SQL, le système sera certainement capable de fonctionner, mais le prix sera très honnête en termes de stockage, de requête, d’échantillonnage, de contrôle de cardinalité et de dépannage humain.

La véritable première décision devrait être celle des indicateurs.

Lorsqu’il y a un problème sur la ligne, la première étape consiste généralement à « juger si cela vaut la peine d’être traité immédiatement ».

Cette étape est la plus adaptée aux indicateurs. En apparence, il semble que l’indicateur soit plus avancé, mais il en est en réalité plus proche et le moins cher.

Un bon système d’indicateurs doit répondre aux questions suivantes en quelques dizaines de secondes :

  • Le taux d’erreur augmente-t-il ou s’agit-il simplement d’un bruit occasionnel ?
  • La variation du délai est-elle globale ou concentrée sur une certaine interface ?
  • L’impact se fait sur une machine, une salle informatique, ou sur l’ensemble de la chaîne d’appel ;
  • Le problème vient-il de se produire ou dure-t-il depuis une demi-heure ?

Ces problèmes ont essentiellement le même objectif : **Utiliser une agrégation d’informations à faible coût en échange de jugements d’action de grande valeur. **

Par conséquent, le principe de conception le plus important des indicateurs est « qu’ils peuvent également soutenir la prise de décision après agrégation ».

De nombreuses équipes créent de mauvais indicateurs en utilisant des champs à cardinalité élevée qui ne devraient pas être inclus dans les indicateurs, tels que user_id, order_id, trace_id, les URL complètes et les messages d’erreur dynamiques. C’est très satisfaisant à court terme et donne l’impression que tout peut être fait ; à moyen terme, l’expansion du stockage, le ralentissement des requêtes et les dimensions des alarmes commenceront à devenir incontrôlables ; le résultat à long terme est généralement que l’équipe elle-même a peur d’utiliser la plateforme d’indicateurs.

Les indicateurs conviennent pour exprimer les tendances et les distributions dans des dimensions stables, telles que les noms d’interface, les codes d’état, les salles informatiques, les services dépendants et les accès au cache. L’intérêt de ces dimensions n’est pas de « restaurer une requête spécifique », mais d’aider à déterminer rapidement si le problème se produit dans les clusters.

Une fois que la question que vous souhaitez poser est « Quelle commande a échoué ? », ce n’est plus une question à laquelle l’indicateur doit répondre seul.

La valeur du Tracing réside dans le raccourcissement du chemin de positionnement

Le traçage est souvent interprété à tort comme une « journalisation plus avancée que la journalisation ». Cela l’utilisera directement.

Ce que Tracing fait vraiment bien, c’est décrire le chemin et la relation chronophage d’une requête entre les services et les composants. Il est naturellement adapté pour répondre à des questions comme celle-ci :

  • La lenteur est-elle causée par la passerelle, l’application, la base de données ou des dépendances externes ?
  • Une nouvelle tentative, dont le saut est amplifié ;
  • Si le P99 d’une certaine interface est si élevé, est-il lié à un certain service en aval ?
  • Une requête anormale commence à s’écarter du chemin normal après être passée par quels services.

En d’autres termes, **Tracing fournit une structure de liens et non une scène complète. **

Par conséquent, ce qu’il devrait contenir le plus, ce sont des informations de chemin, des étapes clés qui prennent du temps et un petit nombre de balises qui peuvent aider au filtrage, plutôt que d’y insérer complètement des objets métier, sans parler de transformer chaque variable locale en un attribut span.

J’ai vu de nombreuses équipes essayer d’en faire une source de vérité unifiée dès qu’elles commencent le traçage : le texte SQL d’origine doit être suspendu, les entrées de l’utilisateur doivent être suspendues, le corps complet de la réponse doit être suspendu et tous les paramètres de nouvelle tentative doivent être suspendus. Le résultat final est :

  • La taille de l’étendue augmente rapidement et le taux d’échantillonnage est obligé d’être réduit ;
  • Lors de l’interrogation du lien, le bruit est bien supérieur au signal ;
  • Lorsque nous sommes effectivement arrivés sur les lieux de l’accident, la demande de clé n’a pas été abandonnée en raison d’un échantillonnage ;
  • La gouvernance des données sensibles commence à devenir un nouveau coût de maintenance.

Le moment le plus précieux pour le traçage est celui où vous pouvez utiliser un lien pour déterminer rapidement quel service, quelle étendue et quelle section de journal doivent être affichés lors du tronçon suivant.

S’il est si lourd qu’il ne peut pas être retenu de manière globalement stable, ou s’il est si lourd qu’il est pénible de l’interroger ne serait-ce qu’une seule fois, alors la frontière a été franchie.

Le journal n’est pas le deuxième système d’indicateurs, c’est le matériel final de collecte de preuves

Le journal est le plus facile à mal évaluer car il semble pouvoir contenir n’importe quoi.

En effet, le journal est le plus proche de la scène. La façon dont la branche a été prise, à quoi ressemblaient les paramètres, combien de fois elle a été réessayée, quel chemin de rétrogradation a été suivi et pourquoi un résultat apparemment réussi mais sémantiquement incorrect a été renvoyé cette fois ne peut souvent être vu qu’à partir des journaux.

Mais précisément parce qu’il possède l’entropie informationnelle la plus élevée, il est le moins adapté à « l’observation globale continue ».

L’utilisation des journaux comme principale source de surveillance a trois conséquences courantes.

Premièrement, le coût des requêtes est élevé. **À chaque fois, des conclusions temporaires sont tirées des faits originaux, ce qui est lent et peu stable.

Deuxièmement, le son est extrêmement bruyant. ** Lorsque le volume du journal est important, l’équipe réduira naturellement l’impression ; une fois l’impression réduite, les branches clés manquent souvent de preuves ; au final, tout le monde fera des allers-retours entre « trop à voir » et « trop peu à voir ».

Troisièmement, cela peut induire de mauvaises habitudes d’ingénierie. ** De nombreux développeurs créent une couche supplémentaire de journalisation lorsqu’ils rencontrent un problème et, par conséquent, le système devient plus bruyant. Ce qui doit vraiment être complété, ce sont les journaux d’événements avec des limites claires, les journaux d’erreurs avec le contexte et les identifiants de requête qui peuvent être associés, plutôt que davantage de « méthodes d’entrée », de « méthodes de sortie », de « démarrage du traitement » et de « traitement terminé ».

L’endroit le plus approprié pour le journal est d’utiliser des indicateurs pour déterminer « il y a vraiment un problème ici » et d’utiliser le traçage pour savoir « le problème réside probablement ici », puis de l’utiliser pour restaurer une demande spécifique.

En d’autres termes, les journaux devraient servir à des fins d’investigation et non de patrouille.

Une simple division du travail est plus efficace que « les trois éléments »

L’approche que je recommande est simple : définissez d’abord la séquence de dépannage, puis définissez les limites de la collection.

Un dépannage en ligne peut se décomposer en trois étapes.

  1. Utiliser d’abord des indicateurs pour déterminer s’il existe des problèmes systémiques ;
  2. Utilisez ensuite le traçage pour faire converger le problème vers l’étape de service et de liaison ;
  3. Enfin, utilisez le journal pour expliquer pourquoi la demande s’est déroulée ainsi.

Si la conception intégrée ne peut pas prendre en charge cette séquence, c’est généralement parce que les responsabilités sont mal attribuées.

Ce qui suit est une manière d’écrire relativement sobre :

func CreateOrder(ctx context.Context, req CreateOrderReq) error {
  start := time.Now()
  defer metrics.OrderCreateLatency.Observe(time.Since(start).Seconds())

  ctx, span := tracer.Start(ctx, "order.create")
  defer span.End()
  span.SetAttributes(
    attribute.String("payment_provider", req.Provider),
    attribute.Bool("has_coupon", req.CouponID != ""),
  )

  err := service.Create(ctx, req)
  if err != nil {
    metrics.OrderCreateErrors.WithLabelValues(classify(err)).Inc()
    logger.Error("create order failed",
      "request_id", requestid.FromContext(ctx),
      "provider", req.Provider,
      "err", err,
    )
    return err
  }
  return nil
}

Il y a ici trois limites intentionnellement restreintes.

  • L’indicateur ne retient que les dimensions qui ont encore une valeur décisionnelle après agrégation, comme les erreurs de classification ;
  • Le traçage ne bloque que quelques attributs qui peuvent aider à filtrer les chemins, plutôt que l’intégralité du corps de la requête ;
  • Le journal enregistre uniquement le contexte clé sur le chemin ayant échoué et est garanti être associé au lien via request_id.

Cette conception n’a rien de sophistiqué, mais elle résout un problème bien réel : après un accident, l’équipe peut-elle aborder la réponse en passant d’un coût faible à un coût élevé, au lieu de se plonger dès le départ dans les données les plus coûteuses. **

Un malentendu courant : comprendre “l’observabilité unifiée” comme “l’agrégation de toutes les données”

De nombreuses plateformes parlent désormais d’observation unifiée. Il n’y a rien de mal à cela en soi, le problème réside dans la manière dont cela est mis en œuvre.

Certaines équipes comprennent l’unification comme « toutes les données entrent sur une seule plateforme, tous les champs sont connectés les uns aux autres et il est préférable de résoudre tous les problèmes avec une seule requête ». Cette idée est tentante car elle semble éliminer les frontières des outils ; mais en ingénierie, cela élimine souvent les limites des coûts.

La bonne direction pour l’unification est de les relier avec un faible frottement.

Par exemple :

  • Les alarmes indicatrices peuvent accéder directement aux services et aux fenêtres horaires pertinents ;
  • le traçage peut trouver le journal correspondant selon request_id ou le code d’erreur ;
  • Les journaux peuvent apporter un contexte de trace au lieu de fonctionner de manière indépendante.

C’est ce qu’on appelle China Unicom, et non un usage mixte.

Le véritable danger est que seule la couche de données la plus lourde peut répondre à toutes les questions.

Contre-exemples et limites : tous les systèmes ne nécessitent pas un ensemble complet de trois pièces

Admettez également que dans certaines scènes, les limites n’ont pas besoin d’être indiquées de manière aussi complète.

Pour les outils internes à faible QPS, les scripts batch autonomes et les tâches hors ligne très stables, les journaux peuvent suffire ; pour les services avec des liens de requête courts et des dépendances simples, les avantages du traçage peuvent ne pas être aussi élevés que prévu ; pour certains scénarios d’audit soumis à des contraintes de conformité, vous ne devez pas vous attendre à ce que le traçage ou les journaux d’application ordinaires servent d’enregistrements d’audit formels.

Cet article dit donc : **Tant que vous décidez de faire trois choses, ne les laissez pas se remplacer. **

Plus le système est complexe, plus les responsabilités doivent être restreintes. Autrement, ce qui est éliminé aujourd’hui, ce sont les limites de conception, et ce qui sera ajouté demain, c’est la facture de la plateforme, le temps de dépannage et la charge cognitive de l’équipe.

Résumé

La chose la plus effrayante à propos de l’observabilité est que chaque couche veut répondre à toutes les questions.

Les indicateurs doivent vous permettre de décider d’agir le plus rapidement possible, le traçage doit vous permettre de décider où chercher en premier le plus tôt possible et les journaux doivent vous informer de ce qui s’est passé le plus rapidement possible.

Si l’ordre de ces trois actions est perturbé, aussi complet soit-il, cela ne fera qu’enterrer encore plus le coût du dépannage.

FAQ

What to read next

Related

Continue reading