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 las que puedan estar distribuidas en varios equipos o procesos. Vea la Información general sobre el 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 aplicación escritos en .NET, las unidades de trabajo en un seguimiento se representan mediante instancias de System.Diagnostics.Activity, y el seguimiento como un conjunto forma un árbol de estas actividades, que puede abarcar muchos procesos distintos. La primera actividad que se crea para una solicitud nueva constituye la raíz del árbol de seguimiento y realiza el seguimiento de la duración total y el é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 realiza, las etiquetas pueden registrar parámetros descriptivos del trabajo y los eventos son un mecanismo de registro sencillo 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". En .NET se adoptó el término "Actividad" hace muchos años, antes de que el nombre "Intervalo" se hubiera establecido correctamente para este concepto.

Identificadores de actividad

Las relaciones primario-secundario entre las actividades del árbol de seguimiento distribuido se establecen mediante identificadores únicos. La implementación de .NET del seguimiento distribuido admite dos esquemas de identificadores: el estándar TraceContext de W3C, que es el valor predeterminado en .NET 5+, y una convención de .NET anterior denominada "Hierarchical" 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 (Activity.TraceId) único global, y todas las actividades dentro del seguimiento tienen asignado un identificador de intervalo único de 8 bytes (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, al agregar una nueva actividad a un seguimiento existente, se utiliza el formato que use la actividad primaria. Si Activity.ForceDefaultIdFormat se establece en true, se invalida este comportamiento y se crean todas las actividades con el valor DefaultIdFormat, incluso cuando el elemento primario usa otro formato de identificador.

Inicio y detención de actividades

Cada subproceso de un proceso puede tener un objeto de Actividad 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 actual en un subproceso y el código inicia una nueva actividad B, B se convierte en la nueva actividad actual en 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.

Coordinación entre límites de proceso

Para poder realizar el seguimiento del trabajo entre límites de proceso, es necesario transmitir los identificadores primarios de actividad por la red para que el proceso de recepción 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. Cuando se usa el formato de identificador Hierarchical, .NET usa un encabezado HTTP de identificador de solicitud personalizado para transmitir el identificador. A diferencia de los entornos de ejecución de otros muchos lenguajes, las bibliotecas incluidas en .NET, como el servidor web ASP.NET y System.Net.Http, comprenden de forma nativa cómo descodificar y codificar los identificadores de actividad en los mensajes HTTP. El entorno de ejecución también entiende cómo fluye el identificador entre las llamadas sincrónicas y asincrónicas. Esto significa que las aplicaciones .NET que reciben y emiten mensajes HTTP participan de forma automática en el flujo de los identificadores de seguimiento distribuido, sin ninguna codificación especial por parte del desarrollador de la aplicación ni dependencias de bibliotecas de terceros. Las bibliotecas de terceros pueden agregar compatibilidad para la transmisión de identificadores mediante protocolos de mensajes distintos de HTTP, o bien para admitir convenciones de codificación personalizadas para HTTP.

Recopilación de seguimientos

El código instrumentado puede crear objetos Activity como parte de un seguimiento distribuido, pero la información de los objetos se debe transmitir y serializar en un almacén persistente centralizado para que todo el seguimiento se pueda revisar de forma útil más adelante. Hay varias bibliotecas de recopilación de telemetría que pueden realizar esta tarea, como Application Insights, OpenTelemetry o una biblioteca proporcionada por un proveedor de telemetría de terceros o 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 conocimientos previos 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 invocando DiagnosticSource.StartActivity y la biblioteca de colecciones debe conocer la información de nomenclatura exacta que el código instrumentado usado al iniciarlo. El uso de DiagnosticSource y DiagnosticListener permite al creador y al cliente de escucha intercambiar objetos de .NET arbitrarios y establecer convenciones personalizadas de paso de información.

muestreo

Para mejorar el rendimiento en aplicaciones de alto rendimiento, el seguimiento distribuido en .NET admite el muestreo solo en un subconjunto de seguimientos en lugar de registrarlos 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, crearla con la información mínima necesaria para propagar los identificadores de seguimiento, o bien rellenarla con la información de diagnóstico completa. Estas opciones compensan la sobrecarga de rendimiento para aumentar la utilidad de diagnóstico. Las actividades que se inician con el patrón anterior de la invocación de Activity.Activity y DiagnosticSource.StartActivity también pueden admitir el muestreo de DiagnosticListener si primero llaman 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 recopilador eficaz, se puede crear, rellenar y transmitir una actividad en acerca de un microsegundo en hardware moderno. El muestreo puede reducir el costo de la instrumentación a menos de 100 nanosegundos para cada actividad que no se registre.

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.