Compartir a través de


Conceptos de seguimiento distribuido de .NET

El seguimiento distribuido es una técnica de diagnóstico que ayuda a los ingenieros a localizar errores y problemas de rendimiento dentro de las aplicaciones, especialmente aquellos que se pueden distribuir entre varias máquinas o procesos. Consulte la Introducción al seguimiento distribuido para obtener información general sobre dónde resulta útil el seguimiento distribuido.

Seguimientos y actividades

Cada vez que una aplicación recibe una nueva solicitud, se puede asociar a un seguimiento. En los componentes de la aplicación escritos en .NET, las unidades de trabajo de un seguimiento se representan mediante instancias de System.Diagnostics.Activity y el seguimiento como un conjunto forma un árbol de estas actividades, que posiblemente abarca muchos procesos distintos. La primera actividad creada para una nueva solicitud forma la raíz del árbol de seguimiento y realiza un seguimiento de la duración general y el control de éxito o error de la solicitud. Opcionalmente, se pueden crear actividades secundarias para subdividir el trabajo en diferentes pasos que se pueden seguir de forma individual. Por ejemplo, dada una actividad que realiza un seguimiento de una solicitud HTTP entrante específica en un servidor web, se podrían crear actividades secundarias para realizar un seguimiento de cada una de las consultas de base de datos necesarias para completar la solicitud. Esto permite que la duración y el éxito de cada consulta se registren de forma independiente. Las actividades pueden registrar otra información para cada unidad de trabajo, como OperationName, pares nombre-valor denominados Tags y Events. El nombre identifica el tipo de trabajo que se está realizando, las etiquetas pueden registrar parámetros descriptivos del trabajo y los eventos son un mecanismo de registro simple para registrar mensajes de diagnóstico con marcas de tiempo.

Nota

Otro nombre común del sector para las unidades de trabajo en un seguimiento distribuido son los "intervalos". .NET adoptó el término "Activity" hace muchos años, antes de que el nombre "Span" se estableciera bien para este concepto.

Identificadores de actividad

Parent-Child relaciones entre las actividades del árbol de seguimiento distribuido se establecen mediante identificadores únicos. La implementación de .NET de seguimiento distribuido admite dos esquemas de identificador: el estándar W3C TraceContext, que es el valor predeterminado en .NET 5+, y una convención anterior de .NET denominada "Jerárquica" que está disponible para la compatibilidad con versiones anteriores. Activity.DefaultIdFormat controla qué esquema de identificador se usa. En el estándar TraceContext de W3C, a cada seguimiento se le asigna un identificador de seguimiento de 16 bytes único global (Activity.TraceId) y a cada actividad dentro del seguimiento se le asigna un identificador de intervalo de 8 bytes único (Activity.SpanId). Cada actividad registra el identificador de seguimiento, su propio identificador de intervalo y el identificador de intervalo de su elemento primario (Activity.ParentSpanId). Como los seguimientos distribuidos pueden realizar el seguimiento del trabajo entre los límites de proceso, las actividades primarias y secundarias podrían no estar en el mismo proceso. La combinación de un identificador de seguimiento y un identificador de intervalo primario puede identificar de forma única la actividad primaria de forma global, independientemente del proceso en el que resida.

Activity.DefaultIdFormat controla qué formato de identificador se usa para iniciar nuevos seguimientos, pero, de forma predeterminada, agregar una nueva actividad a un seguimiento existente usa cualquier formato que use la actividad primaria. Al establecer Activity.ForceDefaultIdFormat en true se invalida este comportamiento y se crean todas las actividades nuevas con DefaultIdFormat, incluso cuando el elemento primario usa un formato de identificador diferente.

Iniciar y detener actividades

Cada subproceso de un proceso puede tener un objeto Activity correspondiente que realice un seguimiento del trabajo que se produce en ese subproceso, accesible a través de Activity.Current. La actividad actual fluye automáticamente a lo largo de todas las llamadas sincrónicas en un subproceso y sigue las llamadas asincrónicas que se procesan en diferentes subprocesos. Si la actividad A es la actividad actual en un subproceso y el código inicia una nueva actividad B, B se convierte en la nueva actividad actual de ese subproceso. De forma predeterminada, la actividad B tratará también la actividad A como su elemento primario. Cuando después se detiene la actividad B, la actividad A se restaurará como la actual en el subproceso. Cuando se inicia una actividad, captura la hora actual como Activity.StartTimeUtc. Cuando se detiene, Activity.Duration se calcula como la diferencia entre la hora actual y la hora de inicio.

Coordinar a través de los límites de procesos

Para realizar un seguimiento del trabajo a través de los límites del proceso, los identificadores primarios de actividad deben transmitirse a través de la red para que el proceso receptor pueda crear actividades que hagan referencia a ellos. Al usar el formato de id. de TraceContext de W3C, .NET también usa los encabezados HTTP recomendados por el estándar para transmitir esta información. Al usar el formato de identificador de Hierarchical, .NET usa un encabezado HTTP de identificador de solicitud personalizado para transmitir el identificador. A diferencia de muchos otros entornos de ejecución de lenguaje, las bibliotecas integradas de .NET, como el servidor web de ASP.NET y System.Net.Http de forma nativa, comprenden cómo descodificar y codificar identificadores de actividad en mensajes HTTP. El tiempo de ejecución también sabe cómo gestionar la propagación del identificador a través de llamadas sincrónicas y asincrónicas. Esto significa que las aplicaciones .NET que reciben y emiten mensajes HTTP participan automáticamente en el flujo de identificadores de seguimiento distribuido, sin codificación especial por parte del desarrollador de la aplicación ni de dependencias de bibliotecas de terceros. Las bibliotecas de terceros pueden agregar compatibilidad para transmitir identificadores a través de protocolos de mensajes que no son HTTP o admitir convenciones de codificación personalizadas para HTTP.

Recolección de trazas

El código instrumentado puede crear Activity objetos como parte de un seguimiento distribuido, pero la información de estos objetos debe transmitirse y serializarse en un almacén persistente centralizado para que todo el seguimiento pueda revisarse de forma útil más adelante. Hay varias bibliotecas de recopilación de telemetría que pueden realizar esta tarea, como Application Insights, OpenTelemetryo una biblioteca proporcionada por una telemetría de terceros o un proveedor de APM. Como alternativa, los desarrolladores pueden crear su propia colección de telemetría de actividad personalizada mediante System.Diagnostics.ActivityListener o System.Diagnostics.DiagnosticListener. ActivityListener admite la observación de cualquier actividad independientemente de si el desarrollador tiene algún conocimiento previo sobre ella. Esto hace que ActivityListener sea una solución de uso general sencilla y flexible. Por el contrario, el uso de DiagnosticListener es un escenario más complejo que requiere que el código instrumentado opte por invocar DiagnosticSource.StartActivity y que la biblioteca de colecciones conozca la información exacta de nomenclatura que el código instrumentado utilizó al iniciarlo. El uso de DiagnosticSource y DiagnosticListener permite al creador y al agente de escucha intercambiar objetos .NET arbitrarios y establecer convenciones de paso de información personalizadas.

Muestreo

Para mejorar el rendimiento de las aplicaciones de alto rendimiento, el seguimiento distribuido en .NET solo admite el muestreo de un subconjunto de seguimientos en lugar de grabarlos todos. En el caso de actividades creadas con la API ActivitySource.StartActivity recomendada, las bibliotecas de recopilación de telemetría pueden controlar el muestreo con la devolución de llamada ActivityListener.Sample. La biblioteca de registro puede optar por no crear la actividad en absoluto, para crearla con información mínima necesaria para propagar identificadores de seguimiento de distribución o para rellenarlo con información de diagnóstico completa. Estas opciones equilibran el aumento de la sobrecarga de rendimiento con el incremento en la utilidad de diagnóstico. Las actividades que se inician con el patrón anterior de invocar Activity.Activity y DiagnosticSource.StartActivity también pueden admitir el muestreo de DiagnosticListener llamando primero a DiagnosticSource.IsEnabled. Incluso al capturar información de diagnóstico completa, la implementación de .NET está diseñada para ser rápida; junto con un colector eficaz, se puede crear, rellenar y transmitir una actividad en alrededor de un microsegundo en hardware moderno. El muestreo puede reducir el costo de instrumentación a menos de 100 nanosegundos para cada actividad que no se registra.

Pasos siguientes

Para obtener un ejemplo de código y empezar a usar el seguimiento distribuido en las aplicaciones .NET, consulte Instrumentación de seguimiento distribuido.

Para obtener una lista de las actividades emitidas de forma nativa por .NET, consulte actividades integradas en .NET.