Video Summary and Transcription
La charla discute la diferencia entre monitoreo y observabilidad, destacando el enfoque de OpenTelemetry en la generación y procesamiento de datos. Explora el concepto de trazas y IDs de span en el rastreo distribuido y la naturaleza experimental de OpenTelemetry en el navegador. La charla también aborda las complejidades de React con componentes de servidor y demuestra cómo el rastreo distribuido puede conectar trazas de diferentes servicios. Se explica el proceso de agregar OpenTelemetry a Next.js y analizar las trazas de la aplicación y del navegador, junto con la importancia de la propagación de contexto. La charla concluye con ideas sobre el análisis de llamadas fetch, errores y las limitaciones de almacenamiento de las trazas.
1. Introducción a la Observabilidad y OpenTelemetry
Hola, soy Jan. Hoy voy a hablar sobre la diferencia entre monitoreo y observabilidad, y profundizar en OpenTelemetry y su rastreo distribuido. La observabilidad es la capacidad de comprender el estado interno del sistema mediante el análisis de los datos generados. OpenTelemetry se centra en generar y procesar datos, mientras que el almacenamiento y análisis son manejados por proveedores. OpenTelemetry también se enfoca en tres datos de telemetría principales: registros, métricas y trazas. Los registros consisten en nombres de campos como la marca de tiempo, ID de traza, ID de span y cuerpo. Las métricas muestran el uso de la CPU en un marco de tiempo específico.
Hola, soy Jan. ¿Alguna vez has tenido la situación en la que recibiste un ticket de error y decía que había una pantalla vacía en algún cliente, y tenías que depurar esto, pero no había forma de encontrar la causa raíz? Bueno, esto no debería ser así. Y por eso te mostraré cómo mejorar los ecosistemas de React con observabilidad y cómo OpenTelemetry te ayudará en ese camino.
Así que hoy voy a hablar sobre la diferencia entre monitoreo y observabilidad. También profundizaré en OpenTelemetry y su rastreo distribuido, y luego te mostraré una demostración rápida de cómo funcionan juntos.
Entonces, ¿cuál es ahora la diferencia entre monitoreo y observabilidad? Bueno, el monitoreo es el proceso de recopilar, analizar y utilizar la información para rastrear algún progreso, alcanzar objetivos o guiar decisiones de gestión. Así que realmente indica lo que está sucediendo. Solo imagina Google Analytics. Te muestra cuántos usuarios hay en esta página o cuántos usuarios abandonaron otra página. Y en base a esta información, puedes guiar algunas nuevas características. ¿Verdad? Así que realmente sabes qué está sucediendo. Por ejemplo, si hay un error, si hay un error que aparece, te muestra qué está sucediendo, pero realmente no te dice la causa raíz. Así que no te ayuda mucho.
Y por eso la observabilidad es muy importante. La observabilidad es la capacidad de comprender el estado interno del sistema mediante el análisis de los datos que genera, como registros, métricas y trazas. Así que te muestra por qué se comporta de esa manera. Y esto es muy importante. Tradicionalmente, hay cuatro problemas principales, generar los datos, procesarlos, almacenarlos y analizarlos. Por lo general, esto viene en una solución de extremo a extremo. Entonces, si quieres cambiar el mecanismo de almacenamiento o análisis, tienes que cambiar todo el proceso. OpenTelemetry lo sabe y en realidad solo se centra en los dos primeros problemas, generar y procesar los datos. El almacenamiento y análisis se harían en los proveedores, en los hombros de los proveedores. OpenTelemetry también se enfoca en tres datos de telemetría principales, registros, métricas y trazas.
Centrándonos en los registros en este momento, estos fueron los más importantes y los más difíciles de implementar, en realidad, porque había tantas implementaciones diferentes en todos los lenguajes y OpenTelemetry está haciendo una semántica consistente para todos los lenguajes. Cuando hablamos de registros en OpenTelemetry, en realidad nos referimos a registros de registro y un registro de registro consiste en estos nombres de campos como la marca de tiempo, un ID de traza, ID de span e incluso el cuerpo, que es la parte más importante. Hablaré más sobre los ID de traza y los ID de span en la sección de trazas. Las métricas son un poco diferentes. Las métricas básicamente te muestran cuánto, por ejemplo, sería el uso de la CPU en un marco de tiempo específico. Las métricas en OpenTelemetry también se llaman medidores e instrumentos, donde un instrumento sería un punto de datos en un momento específico.
2. Comprensión de Trazas e IDs de Span
Entonces, ¿cuánta CPU está utilizando en este momento? Una traza es el recorrido del usuario de un evento específico, como una llamada a la API. Cada ID de traza consta de múltiples IDs de span, que representan diferentes llamadas de función. Los eventos de span son registros que ocurren en momentos específicos en el ID de span.
Entonces, ¿cuánta CPU está utilizando en este momento? Un medidor es algo así como un grupo, por lo que agrupa múltiples instrumentos y, por supuesto, puedes tener varios agrupadores. Las trazas son, nuevamente, un poco diferentes. Entonces, ¿qué es una traza? Básicamente, una traza es el recorrido del usuario de un evento específico. Por ejemplo, en este caso, una llamada a la API. Si alguien realiza una llamada a la API, obtienes un ID de traza específico, que se crea solo para este evento específico. Y cada ID de traza consta de múltiples IDs de span. Un ID de span podría ser una llamada a la base de datos u otra llamada de función. Así que esto podría ser muy aleatorio. Cada ID de span o ID de traza también puede contener atributos clave, que puedes definir fácilmente. Además de los IDs de span, también existen los eventos de span. Un evento de span es algo así como un registro que ocurre en un momento específico en el ID de span. Más adelante en la demostración, te mostraré cómo podría verse un evento de span.
3. Distributed Tracing in the Browser
Un evento de span puede señalar un error, lo que ayuda en la depuración. OpenTelemetry en el navegador es experimental, con discusiones en curso sobre la especificación. Cada interacción del usuario se trata como una traza separada, facilitando la depuración. Las trazas se pueden combinar utilizando atributos clave, como el ID de instancia del servicio.
Y ahora se pone interesante porque un evento de span no solo puede ser un registro, sino que también puede señalar un error. Entonces, si algo sucede y tienes un evento de span en un ID de span que dice que esto es un error, inmediatamente puedes ver a través de esta traza que la API hizo algo mal. Y según lo que se haya llamado, sabes qué está sucediendo en el sistema. Y esto es realmente útil en la depuración.
Entonces, ¿cómo funciona OpenTelemetry en el navegador? Bueno, en primer lugar, OpenTelemetry aún no está realmente especificado en el navegador. Así que es muy experimental. Y ahora mismo hay muchas solicitudes de extracción abiertas sobre cómo especificarlo por los grupos de OpenTelemetry. Entonces, en este momento, cómo funciona es el rastreo del frontend, por lo que generalmente tienes un recorrido de un usuario de una sesión de usuario, que puede durar tres horas, cuatro horas o incluso más. Y no quieres tener un ID de traza para todo el recorrido. Esto sería demasiado difícil de depurar.
Lo que haces ahora es que cada interacción del usuario sería una traza. Por ejemplo, si una persona recarga la página, tienes una traza, que es una carga de documento que carga diferentes archivos como archivos HTML, archivos CSS y así sucesivamente. A lo largo del recorrido, tal vez haya una solicitud aleatoria en segundo plano, que crea otra traza. Y, por supuesto, una interacción aleatoria del usuario. Entonces, un clic del usuario, que luego también se dirige a diferentes puntos finales de la API. A veces aún quieres combinar esas trazas en una sola, y esto no se hace con un ID de traza, sino con atributos clave, como mencioné antes, en este caso, el ID de instancia del servicio. Esto sería un identificador único que agregas a cada una de las diferentes trazas.
4. React Complexity and Server Components
Puedes agregar el ID de instancia del servicio a cada traza. La complejidad de React aumenta con los componentes del servidor, especialmente durante la carga de páginas y transiciones. Max descubre las complejidades de React con los componentes del servidor, que involucran Redis y Nginx.
Entonces puedes decir, hey, este es el ID de instancia del servicio, y este es el ID de instancia del servicio. Y puedes agregar eso a cada una de estas trazas. Más adelante puedo mostrarte más en una demostración a qué me refiero con eso.
Hablemos un poco de la complejidad en React y Web. Específicamente, la complejidad en React se vuelve un poco más interesante con los componentes del servidor, porque en la carga inicial de la página, un componente del servidor no parece un componente del servidor para el usuario, porque se implementa de inmediato en el HTML. Entonces el usuario simplemente cambiaría a una página diferente, por ejemplo, la página de diseños.
Y esta página de diseños también tiene componentes del servidor. Esta no se obtiene como HTML. En realidad, se obtiene como una solicitud de API fetch, una solicitud POST, lo que hace todo un poco más interesante para depurar. Entonces, ¿cómo se ve ahora la complejidad en la web? Ahí está Max, y Max es bastante nuevo en React, ¿verdad? Y pronto Max descubre que React es un poco más complicado con los componentes del servidor, ya que en los componentes del servidor, puedes ir directamente a Redis y obtener algunas claves o puedes llamar a otro punto final, que es un Nginx, que también consta de un evento Python o un servicio Python, que también tiene acceso a Redis.
5. Distributed Tracing and Next.js Demo
Max sigue feliz. El rastreo distribuido conecta trazas de diferentes servicios utilizando la propagación de contexto. El contexto de trazas de W3C permite combinar los ID de trazas de los servicios. La demostración muestra el playground de la aplicación Next.js y cómo agregar OpenTelemetry a los servicios.
De todos modos, Max es un ingeniero muy feliz y quiere aprender cosas, así que no te preocupes, Max sigue feliz. Así que hablemos un poco sobre el rastreo distribuido. ¿Qué es el rastreo distribuido? Básicamente, se trata de conectar una traza para diferentes servicios. Así que tienes un servicio de React y un servicio de Nginx y quieres combinarlos. Y esto funciona con la propagación de contexto. Un contexto sería un servicio. Entonces, el servicio de React sería un contexto. Y lo mismo ocurre con el servicio de Nginx en el otro lado. Esto también es un contexto.
En el medio, necesitas propagar la traza, que en total se llama propagación de contexto, que también es rastreo distribuido. Y como puedes ver, ves un ID de traza completo sobre todo el span. Entonces, ¿cómo funciona ahora que un ID de traza ahora consiste o incluye ambos servicios? Bueno, esto se hace con el encabezado de contexto de traza de W3C. En este caso, este es el encabezado de traza principal, que está definido por el contexto de traza de W3C. También hay diferentes técnicas como B3 o algo diferente. Entonces, con el contexto de traza de W3C, tenemos el traza principal, que consta de cuatro componentes principales como el primero, el 0.0, que es la versión, el ID de traza, que es el ID de traza que conecta ambos servicios y el ID de span, que es el último ID de span del servicio de React, que hace el primer ID de span del siguiente servicio. Entonces, esta es la conexión entre A y B. Y el último componente es básicamente si está muestreado o no. Puedes leer toda la especificación en el contexto de traza de W3C.
Entonces, profundicemos un poco en la demostración. Preparé el playground de la aplicación Next.js, que es de código abierto, y puedes usarlo por ahora. Y también agregué y puedes revisar el repositorio al final de la presentación. Un commit y un commit realmente agrega OpenTelemetry a nuestros servicios. Puedes ver cómo se introdujo OpenTelemetry aquí. No hablaré sobre Nginx porque tengo un Nginx aquí. Solo hablaré sobre Next.js y Browser.js. Entonces, instrumentar OpenTelemetry en JavaScript es un poco más complicado y Next.js lo sabe. Entonces, escribieron un pequeño ayudante para nosotros. Escribieron el ayudante register hotel y nos dan algunas opciones. Por ejemplo, el nombre del servicio. El nombre del servicio es básicamente la introducción o el nombre previsto para el servicio.
6. Adding OpenTelemetry to Next.js
La introducción o el identificador sobre cómo se llamará nuestro contexto más adelante cuando analicemos las trazas. OpenTelemetry en el navegador es experimental. Next.js no ofrece la opción de OpenTelemetry en el navegador. Agregar OpenTelemetry requiere un proveedor, procesamiento de trazas y un exportador.
La introducción o el identificador sobre cómo se llamará nuestro contexto más adelante cuando analicemos las trazas. Además, por cierto, todavía es experimental. Es por eso que es un gancho de instrumentación experimental. Además, dado que OpenTelemetry en el navegador es muy experimental, Next.js no ofrece esa opción. Pero me presenté y aquí puedes ver los conceptos básicos de cómo agregar OpenTelemetry. En este caso, te muestro una pequeña introducción del archivo en sí. Entonces, aquí tienes lo mismo que teníamos antes con la aplicación Next, pero con la aplicación Next en el navegador. Entonces, en el navegador, esto sería nuestro propio servicio encapsulado. Y también tenemos el ID de sesión del recorrido del usuario. Entonces, en este caso, cada vez que recargas, obtienes un UUID dedicado solo para toda la sesión. Y cada ID de traza también obtiene exactamente este UUID. Además de OpenTelemetry, solo para que lo sepas, necesitamos un proveedor. Necesitamos algún tipo de procesamiento para trazas o spans, en realidad. Y luego necesitamos un exportador. ¿A dónde va? Está el exportador de trazas OTLB, que es el exportador de trazas del protocolo OpenTelemetry. O, por ejemplo, diferentes como el exportador de console, cuando tienes un. Simplemente lo imprime directamente en la console.
7. Analyzing Application and Browser Traces
La aplicación tiene varias cosas en marcha, como la página de diseño, HTML, JavaScript, SVG y pre-renderización para los componentes del servidor. Las trazas se envían al colector de OpenTelemetry, que luego se muestra en la interfaz de usuario de Jaeger. La propagación de contexto ocurre entre el backend y el frontend a través de la ingestión del padre de traza en el contexto del frontend. Las trazas del frontend del navegador muestran los recursos obtenidos, siendo el más largo la instrumentación del navegador, que aún está en fase experimental.
Entonces, vamos a entrar en la aplicación. Cuando recargo ahora, puedes ver que muchas cosas están sucediendo. Así que está la página de diseño, el HTML, que básicamente tarda mucho tiempo en 400 milisegundos. Y se carga como cualquier otra página, mucho JavaScript, algunos SVG, etc. Next.js también está haciendo algo de pre-renderización aquí para los componentes del servidor, para algunos mecanismos de caché. Y lo más importante, enviamos las trazas directamente a nuestro colector de OpenTelemetry. Hablaré un poco sobre el colector de OpenTelemetry al final de la presentación.
Entonces, estas trazas ahora se enviaron a nuestro Jaeger UI a través del colector de OpenTelemetry. Y Jaeger UI básicamente te muestra las trazas, ¿verdad? Así que esa es la aplicación del navegador Next, por ejemplo. Hay la aplicación Next y la siguiente. Voy a quitar el texto por ahora. Podemos ignorar el Jaeger todo en uno. Así que hay tres diferentes en los que queremos enfocarnos. Y por ahora, queremos profundizar en las trazas del navegador de la aplicación Next. Así que si ahora mostramos todas las trazas, podemos ver que muchas cosas están sucediendo. Así que hay una en la primera, nuestro coche principal, y luego algunos otros coches. Así que si nos adentramos más en estos, y este, podemos ver en las etiquetas, que básicamente solo se obtuvo esta URL.
Si queremos profundizar en la recarga principal, que es esta, ya podemos ver que alcanzamos nuestro H y X, que luego propagó correctamente el contexto a la siguiente aplicación. Y la siguiente aplicación movió correctamente el contexto hacia el navegador. Entonces, ¿cómo funciona la propagación de contexto entre el backend y el frontend? Bueno, aquí encontrarás los propagadores en la implementación del navegador. Y también definimos el propagador de contexto de traza W3C, que básicamente toma la etiqueta del medidor de la cabeza, que es el padre de traza, y lo ingiere en el contexto del frontend. Esto se hace en el archivo layout TSX. En el archivo layout TSX, podemos agregar encabezados o cabeceras y todo al diseño base. Y también agregaron la etiqueta del medidor del padre de traza, donde tenemos todos estos cuatro componentes. El primero, la versión, el ID de traza, el último ID de span del servidor, porque se renderiza en el servidor, ¿verdad? Y el 01, que básicamente indica si está muestreado o no. Muy bien, y ahora echemos un vistazo más de cerca a las trazas del frontend del navegador. Y aquí ya podemos ver que se obtuvieron algunos recursos. El más largo, que es este, sería la instrumentación del navegador. Actualmente, como dije, la instrumentación del navegador aún no es estable. Todavía está en fase experimental.
8. Analyzing Fetch Calls and Errors
OpenTelemetry fue diseñado para Node.js pero carece de algunas funcionalidades de tree shaking. El tiempo de carga de la página se ve afectado por las llamadas fetch, y optimizar con OpenTelemetry puede ayudar. Al hacer clic en electrónicos se produjo un retraso debido a las llamadas fetch. Varios usuarios generan múltiples trazas, y los recorridos de los usuarios se pueden analizar utilizando IDs de instancia de sesión. Los errores se pueden desencadenar en el área de juegos de la aplicación.
Y fue diseñado específicamente para Node.js. Por lo tanto, todas las funcionalidades de tree shaking aún no están disponibles. Y este es un proceso en curso para hacerlo aún más rápido y más pequeño.
Entonces, de inmediato, puedes ver por qué esta carga de página completa tomó casi 400 milisegundos. Es debido a una de estas llamadas fetch. Entonces, esta llamada fetch hizo que todo se alargara. Si quieres que tus tiempos de carga sean más rápidos, con OpenTelemetry, puedes ver dónde puedes optimizar eso. Si tuvieras una llamada a la base de datos aquí, también verías otra traza.
¿Qué sucedería ahora si haces clic en electrónicos? Puedes ver que hubo un pequeño retraso. Tomó un poco de tiempo. Si verificas la parte de electrónicos, también puedes ver que tomó 450 milisegundos. Entonces, si ahora reviso el Jaeger UI y reviso todas mis trazas, y también elimino todo el ruido aquí, que son los 400 milisegundos, ya puedes ver que hay una llamada con 417 milisegundos. Si reviso esta llamada dentro de las etiquetas, puedes ver que hay un componente de servidor de electrónicos. Entonces, ¿por qué ahora esto tomó más tiempo de lo esperado? Bueno, ya vemos que hay dos llamadas fetch una después de la otra. Entonces, una optimización podría ser simplemente paralelizarlas. O confiar en Next.js y después de la segunda carga, todo estaría en caché de todos modos. Bueno, ¿qué sucedería si hubiera 100 usuarios? Entonces, si vuelvo a cargar ahora varias veces, tres, cuatro veces, ya no tengo 10 trazas, sino varias. Entonces, cuando vuelvo al Jaeger UI y encuentro las trazas, sin la duración mínima, por supuesto, puedo ver que hay 20 trazas. Luego puedo ver que hay 20 trazas, que son múltiples sesiones. Podrían ser múltiples usuarios. Por ejemplo, si tengo a una persona con una carga de página enorme, puedo verificarlas yendo al navegador de la aplicación Next. Y en el proceso, básicamente tenemos etiquetas adicionales, que son el ID de instancia de sesión, que es compartido para cada sesión. Y también puedo filtrarlas por etiquetas. Así que simplemente las coloco aquí y solo tengo 12 etiquetas. 12 trazas. Ahora puedo ver el recorrido del usuario para esta persona específica, lo cual es bastante útil si quieres analizarlo y profundizar en él. Entonces, ¿qué pasa con los errores en este momento? Porque antes mencioné los eventos de gasto, preparé algo aquí. Entonces, si mueves el área de juegos de la aplicación, también puedes desencadenar algunos errores. Y en este caso, lo modifiqué para que devuelva un 500 porque a veces puede suceder. Esta sería ahora la página en blanco.
9. Analyzing Errors and Error Locations
Las barreras de error de Next.js muestran el componente de error en lugar de una página en blanco. Se detectaron dos errores en las trazas, que involucran componentes y registros del backend. Los mapas de origen en Grafana o DireTrace pueden proporcionar trazas de pila detalladas y ubicaciones de errores.
Afortunadamente, una vez más, Next.js tiene algunas barreras de error y muestra el componente de error en lugar de una página en blanco. Pero aún así obtuvimos un 500. En las propias trazas, si queremos encontrar las trazas y otra sesión, por supuesto, podemos ver de inmediato que hubo dos errores. Entonces, si lo analizamos aún más, podemos ver que hubo dos componentes que tuvieron un error. El nginx, que técnicamente solo devolvió un 500. Entonces, básicamente, no fue culpa del nginx, pero continuó hacia el backend y el backend agregó un registro. En este caso, se llama registros, pero técnicamente es un evento de gasto. Y aquí ya vemos que hay una excepción en curso. Entonces, un evento, que es una excepción, un mensaje, esto no sucedería normalmente, y la traza de la pila. Desafortunadamente, Jager no proporciona cargas web de origen, pero proveedores como Grafana o DireTrace sí lo hacen. Y luego simplemente puedes cargar tus mapas de origen, y luego verías de inmediato todas las trazas de pila y lo que se capturó y todo. Así que de la nada, sin conocer el código, ya puedes ver dónde está el problema, y puedes señalar la ubicación exacta del error.
10. Traces, Storage, and Open Telemetry Collector
Agregar trazas en todas partes puede no ser práctico debido a las limitaciones de almacenamiento. Grafana ofrece almacenamiento gratuito con límites mensuales, pero los gigabytes adicionales tienen un costo. Mitigue esto utilizando el colector de telemetría abierto, que permite procesar y filtrar datos antes de exportarlos a un host económico o discreto. La instrumentación automática de telemetría abierta es suficiente, y la propagación de contexto es crucial para comprender las llamadas de servicio y reducir costos.
Y esto fue todo para mi demostración. Así que volvamos a la presentación. Ahora pensarías, bien, agreguemos trazas en todas partes, porque así sabremos qué está sucediendo, ¿verdad? No, no deberías hacerlo. Quiero decir, técnicamente deberías hacerlo, pero el problema es que los data deben almacenarse en algún lugar.
Por ejemplo, está Grafana, que técnicamente es gratuito para siempre, pero debes mirar más de cerca porque hay límites mensuales. Por ejemplo, para registros, trazas y perfiles, tienes 50 gigabytes cada uno para una retención de 14 días. Si tienes varios usuarios y rastreas todo, es posible que tengas más de 50 gigabytes. Bueno, entonces simplemente actualizo a la versión Pro y pago según uso, pero aún tengo las trazas de 50 gigabytes de forma gratuita, pero cada gigabyte adicional ahora cuesta 50 centavos, lo cual no es mucho a simple vista. Pero si tienes muchos gigabytes, esto podría sumar mucho a tu salario mensual. Aquí puedes ver los 50 centavos por gigabyte.
Entonces, ¿cómo puedes mitigar esto? Hay una gran solución, que se llama el colector de telemetría abierto, que también es parte de mi ejemplo que te mostré antes. Tienes varios receptores y uno de los receptores podría ser múltiples instancias. Por ejemplo, mi aplicación Next.js, sería uno de estos receptores porque enviamos los data directamente al colector. También podría ser un archivo o algo diferente. Mientras tanto, en el medio, procesas los data. Puedes filtrar cosas, moverlo a una ubicación diferente y cosas así. Y esto es importante porque el exportador en el lado derecho es importante porque puedes enviar una línea de registro, que consiste en un error, a low key. Low key es básicamente la parte interesante para los registros en Grafana. O simplemente puedes guardarlo en un archivo, que se encuentra en un host muy económico donde puedes tener mucho espacio en disco, ¿verdad? Y así es como ahorras dinero. También puedes agregar muestreo en la telemetría abierta. Esto también se agrega en uno de mis ejemplos. Las conclusiones clave ahora son que la instrumentación automática de telemetría abierta está haciendo el trabajo pesado. Aún puedes hacer instrumentación manual, pero la instrumentación automática ya es suficiente. Además, la telemetría abierta del navegador aún no está especificada como muy experimental. Y también la propagación de contexto es realmente importante porque necesitas tener una imagen más completa. Necesitas saber qué servicio se llama. Y, por supuesto, el colector puede reducir costos. Así que por favor utiliza esto porque es esencial. Esta fue mi charla. Muchas gracias. Trabajo en DevOpsCycle como cofundador y también trabajo en Dynatrace como ingeniero de software. Gracias.
Comments