Integración de OpenTelemetry en la arquitectura de referencia de aplicaciones modernas: informe de progreso

NGINX | 08 de marzo de 2022

Cuando presentamos la arquitectura de referencia de NGINX para aplicaciones modernas (MARA) el pasado otoño en Sprint 2.0, recalcamos que nuestra intención no era que fuese un «juguete» como algunas arquitecturas, sino una solución «sólida, probada y lista para implementarse en aplicaciones de producción reales que se ejecutan en entornos de Kubernetes». Para un proyecto de este tipo, las herramientas de observabilidad son un requisito indispensable. Todos los miembros del equipo de MARA hemos comprobado de primera mano cómo la falta de visibilidad sobre el estado y el rendimiento convierte el desarrollo y la entrega de aplicaciones en un ejercicio frustrante. De inmediato llegamos al consenso de que MARA debía incluir instrumentación para la depuración y el seguimiento en un entorno de producción.

Otro principio rector de MARA es la preferencia por las soluciones de código abierto. En este artículo, explicamos cómo nuestra búsqueda de una herramienta de observabilidad multifuncional y de código abierto nos llevó a OpenTelemetry, y detallamos las ventajas e inconvenientes, las decisiones de diseño, las técnicas y las tecnologías que utilizamos para integrar OpenTelemetry en una aplicación de microservicios desarrollada con Python, Java y NGINX.

Esperamos que conocer nuestras experiencias le ayude a evitar posibles dificultades y a acelerar su propia adopción de OpenTelemetry. Tenga en cuenta que esta publicación es un informe de progreso sujeto al paso del tiempo; prevemos que las tecnologías que analizamos madurarán en el plazo de un año. Además, aunque señalamos las carencias actuales de algunos proyectos, estamos enormemente agradecidos por todo el trabajo de código abierto que se está realizando y nos entusiasma ver cómo evoluciona.

Nuestra aplicación

Como aplicación que integrar con una solución de observabilidad, elegimos Bank of Sirius, nuestra bifurcación de la aplicación de ejemplo Bank of Anthos de Google. Es una aplicación web con una arquitectura de microservicios que puede desplegarse mediante infraestructura como código. Esta aplicación puede mejorarse de muchas maneras en términos de rendimiento y fiabilidad, pero tiene la madurez suficiente como para considerarla razonablemente una aplicación brownfield. Por ello, creemos que es un buen ejemplo para mostrar cómo integrar OpenTelemetry en una aplicación, ya que, en teoría, el rastreo distribuido aporta información valiosa sobre las deficiencias de la arquitectura de una aplicación.

Como se muestra en el diagrama, los servicios que sustentan la aplicación son relativamente sencillos.

Imagen cortesía de Google

Cómo elegimos OpenTelemetry

El proceso que nos llevó a elegir OpenTelemetry fue bastante sinuoso y constó de varias etapas.

Crear una lista de funcionalidades deseadas

Antes de evaluar las herramientas de observabilidad de código abierto disponibles, identificamos qué aspectos de la observabilidad nos importaban. Basándonos en nuestra experiencia previa, elaboramos la siguiente lista.

  • Registro – Tal como utilizamos el término, se refiere a la generación por parte de las aplicaciones de conjuntos clásicos de mensajes delimitados por saltos de línea; la aplicación Bank of Sirius estructura sus registros en formato Bunyan
  • Trazabilidad distribuida – Tiempos y metadatos de cada componente de toda la aplicación, como los que proporcionan los proveedores de gestión del rendimiento de aplicaciones (APM)
  • Métricas – Mediciones recopiladas durante un periodo de tiempo y representadas gráficamente como datos de series temporales
  • Agregación y notificación de excepciones/errores – Una recopilación agregada de las excepciones y los errores más frecuentes, en la que se puedan realizar búsquedas para determinar cuáles son los errores más comunes de la aplicación
  • Comprobaciones de estado – Sondeos periódicos enviados a los servicios para determinar si funcionan correctamente dentro de la aplicación
  • Introspección del estado de ejecución – Un conjunto de API visibles únicamente para los administradores que proporcionan información sobre el estado de ejecución de la aplicación
  • Volcados de memoria y de núcleo – Instantáneas completas del estado de ejecución de un servicio; para nuestros fines, el factor importante es la facilidad con la que se pueden obtener estos volcados bajo demanda o cuando un servicio falla

Comparación de las funciones de las herramientas con la lista de requisitos

Por supuesto, no esperábamos que una única herramienta o enfoque de código abierto incluyera todas estas funcionalidades, pero al menos nos proporcionó una base de referencia ideal con la que comparar las herramientas disponibles. Consultamos la documentación de cada herramienta para averiguar cuáles de las siete funcionalidades de nuestra lista de deseos admite. La tabla resume nuestras conclusiones.

Tecnología Registro Seguimiento distribuido Métricas Agregación de errores Comprobaciones de estado Introspección en tiempo de ejecución Volcados de memoria dinámica/núcleoELK + Elastic APM ✅ ✅ ✅ ✅ ✅ ❌ ❌Grafana ✅ ✅ ✅ ✅ ✅ ❌ ❌Graylog ✅ ❌ ❌ ❌ ❌ ❌ ❌Jaeger ❌ ✅ ❌ ✅ ❌ ❌ ❌OpenCensus ❌ ❌ ✅ ❌ ❌ ❌ ❌OpenTelemetry Beta ✅ ✅ ✅ ✅ * ❌ ❌Prometheus ❌ ❌ ✅ ❌ ❌ ❌ ❌StatsD ❌ ❌ ✅ ❌ ❌ ❌ ❌Zipkin ❌ ✅ ❌ ✅ ❌ ❌ ❌

* Como extensión

Elaborar esta tabla fue un duro golpe de realidad. Las distintas herramientas difieren tanto en sus capacidades y finalidades que no podíamos considerarlas parte de una misma categoría: ¡era como comparar manzanas con tostadoras!

Por ejemplo, ELK (Elasticsearch-Logstash-Kibana, además de Filebeat) y Zipkin hacen cosas tan radicalmente distintas que intentar compararlos resulta más confuso que esclarecedor. Por desgracia, la «ampliación descontrolada del alcance» no hace sino enturbiar aún más las aguas: sin duda, en respuesta a las peticiones de los usuarios, se han añadido funciones secundarias respecto al propósito principal de la herramienta y que se solapan con las de otras herramientas. A primera vista, ELK se encarga del almacenamiento y la visualización de registros, mientras que Zipkin se ocupa del rastreo distribuido. Pero, al profundizar un poco más en la cartera de productos de Elastic, enseguida aparece Elastic APM, que admite el rastreo distribuido e incluso es compatible con Jaeger.

Más allá del problema de la ampliación progresiva de objetivos, muchas de las herramientas pueden integrarse entre sí, lo que da lugar a distintas combinaciones de recopiladores, agregadores, paneles de control, etc. Algunas de las tecnologías son compatibles entre sí y otras no.

Realización de una investigación cualitativa

Por tanto, esta tabla comparativa no nos ofrecía una visión lo bastante precisa como para basar nuestra elección en ella. Necesitábamos realizar una investigación cualitativa de los objetivos, los principios rectores y la posible evolución futura de cada proyecto, partiendo de la idea de que, cuanto más se asemejen los valores de un proyecto a los nuestros, más probable será que sigamos siendo compatibles con el paso del tiempo. Al visitar las páginas de los proyectos, enseguida observamos esto en la página de OpenCensus.

OpenCensus y OpenTracing se han fusionado para crear OpenTelemetry, que constituye la siguiente versión principal de OpenCensus y OpenTracing. OpenTelemetry ofrecerá compatibilidad con las integraciones existentes de OpenCensus, y seguiremos publicando parches de seguridad para las bibliotecas existentes de OpenCensus durante dos años.

Ese fue un dato clave para nosotros. Sabíamos que no podíamos garantizar que nuestra elección estuviera preparada para el futuro, pero al menos queríamos asegurarnos de que contaría con un sólido respaldo de la comunidad en adelante. Con esta información, podíamos descartar OpenCensus de nuestra lista de candidatos. Probablemente tampoco fuera buena idea utilizar Jaeger, ya que es la implementación de referencia del proyecto OpenTracing —ahora oficialmente obsoleto— y la mayoría de las nuevas contribuciones se incorporarán a OpenTelemetry.

Después, nos informamos sobre OpenTelemetry Collector.

OpenTelemetry Collector ofrece una implementación independiente del proveedor para recibir, procesar y exportar datos de telemetría. Además, elimina la necesidad de ejecutar, operar y mantener varios agentes o recopiladores para admitir formatos de datos de telemetría de código abierto (por ejemplo, Jaeger, Prometheus, etc.) y enviarlos a múltiples back-ends comerciales o de código abierto.

OpenTelemetry Collector actúa como un agregador que nos permite combinar distintos métodos de recopilación e instrumentación de observabilidad con diferentes backends. Básicamente, nuestra aplicación puede recopilar trazas con Zipkin y métricas de Prometheus, que después podemos enviar a un backend configurable y visualizar con Grafana. Este diseño admite muchas otras combinaciones, por lo que podemos probar distintos enfoques para determinar qué tecnologías se adaptan mejor a nuestro caso de uso.

Integrar OpenTelemetry como camino a seguir

En esencia, el OpenTelemetry Collector nos convenció porque, en teoría, nos permite cambiar de una tecnología de observabilidad a otra. A pesar de la relativa inmadurez del proyecto, decidimos lanzarnos de lleno y utilizar OpenTelemetry únicamente con integraciones de código abierto, porque la única forma de comprender el panorama es utilizar las tecnologías.

Sin embargo, OpenTelemetry Collector carece de algunos componentes, por lo que tenemos que recurrir a otras tecnologías para disponer de esas funcionalidades. En las siguientes secciones se resumen nuestras elecciones y los motivos que las justifican.

Implementación del registro

El registro es una parte de la observabilidad aparentemente sencilla, pero que enseguida obliga a tomar decisiones complejas. Es sencillo porque basta con recopilar la salida de los registros de los contenedores, pero resulta complejo porque después hay que decidir dónde almacenar los datos, cómo transferirlos a ese almacén, cómo indexarlos para que sean útiles y durante cuánto tiempo conservarlos. Para que los archivos de registro resulten útiles, deben poder consultarse fácilmente mediante suficientes criterios diferentes como para satisfacer las necesidades de los distintos usuarios.

Analizamos la compatibilidad con el registro de logs de OpenTelemetry Collector y, en el momento de redactar este texto, se encuentra en una fase beta muy temprana. Decidimos utilizar ELK para el registro de logs a corto plazo mientras seguimos investigando otras opciones.

A falta de una razón de peso para no hacerlo, optamos por utilizar las herramientas de Elasticsearch, lo que nos permitió dividir el despliegue en nodos de ingesta, coordinación, maestros y de datos. Para facilitar el despliegue, utilizamos un chart de Bitnami. Para transportar los datos, desplegamos Filebeat como parte de un DaemonSet de Kubernetes. Añadimos la funcionalidad de búsqueda mediante el despliegue de Kibana y aprovechamos los índices, las búsquedas, las visualizaciones y los paneles precargados.

Pronto quedó claro que, aunque esta solución funcionaba, la configuración predeterminada consumía bastantes recursos, lo que dificultaba su ejecución en entornos con menos recursos, como K3S o Microk8s. Añadir la posibilidad de ajustar el número de réplicas de cada componente resolvió este problema, pero provocó algunos fallos que podrían haberse debido al agotamiento de los recursos o a un volumen excesivo de datos.

Lejos de sentirnos decepcionados por ello, lo vemos como una oportunidad para evaluar el rendimiento de nuestro sistema de registro con distintas configuraciones, así como para investigar otras opciones como Grafana Loki y Graylog. Es posible que descubramos que las soluciones de registro más ligeras no ofrecen todas las funciones que algunos usuarios necesitan y que sí pueden obtener con herramientas que consumen más recursos. Dada la naturaleza modular de MARA, probablemente desarrollaremos módulos adicionales para estas opciones con el fin de ofrecer a los usuarios más alternativas.

Implementación del rastreo distribuido

Además de determinar qué herramienta ofrece la funcionalidad de rastreo que buscamos, tuvimos que plantearnos cómo implementar la solución y qué tecnologías debían integrarse con ella.

En primer lugar, queríamos asegurarnos de que la instrumentación no afectara negativamente a la calidad del servicio de la propia aplicación. Todos habíamos trabajado con sistemas cuyo rendimiento disminuía de forma predecible una vez por hora mientras se exportaban los registros, y no teníamos ningún deseo de repetir aquella experiencia. La arquitectura de OpenTelemetry Collector resultaba atractiva en este sentido, ya que permite ejecutar una instancia por host. Cada recopilador recibe datos de los clientes y agentes de las distintas aplicaciones que se ejecutan en el host, ya estén en contenedores o no. El recopilador agrega y, si procede, comprime los datos antes de enviarlos a un sistema de almacenamiento, lo que nos pareció ideal.

A continuación, evaluamos la compatibilidad con OpenTelemetry en los distintos lenguajes de programación y frameworks que utilizamos en la aplicación. En este punto, la situación se complicó un poco. A pesar de utilizar únicamente los dos lenguajes de programación y los frameworks asociados que se muestran en la tabla, el nivel de complejidad resultó sorprendentemente alto.

Lenguaje Framework Número de serviciosJava Spring Boot 3Python Flask 3

Para añadir trazabilidad a nivel de lenguaje, primero probamos los agentes de instrumentación automática de OpenTelemetry, pero nos pareció que la información que generaban estaba desordenada y resultaba confusa. Estamos seguros de que esto mejorará a medida que maduren las bibliotecas de instrumentación automática, pero, por el momento, descartamos los agentes de OpenTelemetry y decidimos integrar la trazabilidad en nuestro código.

Antes de lanzarnos a implementar directamente el rastreo en el código, configuramos OpenTelemetry Collector para que enviara todos los datos de rastreo a una instancia de Jaeger que se ejecutaba localmente, donde podíamos ver el resultado con mayor facilidad. Esto nos resultó muy útil, ya que pudimos experimentar con la presentación visual de los datos de rastreo mientras determinábamos cómo integrar OpenTelemetry por completo. Por ejemplo, si descubríamos que una biblioteca cliente HTTP no incluía datos de rastreo al realizar llamadas a un servicio del que dependía, añadíamos de inmediato el problema a nuestra lista de correcciones. Jaeger ofrece una buena vista de todos los tramos que componen una misma traza:

Rastreo distribuido para Python

Añadir trazabilidad a nuestro código Python fue relativamente sencillo. Añadimos dos archivos de código fuente de Python a los que hacen referencia todos nuestros servicios y actualizamos los archivos requirements.txt correspondientes para incluir las dependencias pertinentes de opentelemetry-instrumentation-*. Esto nos permitió utilizar la misma configuración de trazabilidad para todos los servicios de Python, así como incluir el ID de traza de cada solicitud en los mensajes de registro e incorporarlo en las solicitudes a los servicios dependientes.

Trazabilidad distribuida para Java

A continuación, centramos nuestra atención en los servicios Java. Usar directamente las bibliotecas Java de OpenTelemetry en un proyecto nuevo es relativamente sencillo: solo hay que importar las bibliotecas necesarias y usar directamente la API de trazado. Sin embargo, si utilizas Spring como nosotros, tendrás que tomar algunas decisiones adicionales.

Spring ya cuenta con una API de rastreo distribuido, Spring Cloud Sleuth. Esta proporciona una fachada sobre la implementación de rastreo distribuido subyacente que, según se describe en la documentación, hace lo siguiente:

  • Añade los identificadores de traza y de segmento al MDC de Slf4J, para que puedas extraer de un agregador de registros todos los registros correspondientes a una traza o un segmento determinados.
  • Instrumenta los puntos habituales de entrada y salida de las aplicaciones Spring (filtro de servlets, RestTemplate, acciones programadas, canales de mensajes y cliente Feign).
  • Si spring-cloud-sleuth-zipkin está disponible, … [genera y notifica] trazas compatibles con Zipkin mediante HTTP. De forma predeterminada, las envía a un servicio recopilador de Zipkin en localhost (puerto 9411). Configure la ubicación del servicio mediante spring.zipkin.baseUrl.

La API también nos permite añadir trazas a las tareas anotadas con «@Scheduled».

En otras palabras, con Spring Cloud Sleuth obtenemos de forma predeterminada trazas en el nivel de los endpoints del servicio HTTP, lo cual supone una ventaja considerable. Como nuestro proyecto ya utiliza Spring, decidimos mantenerlo todo dentro de ese framework y aprovechar las funcionalidades que ofrece. Sin embargo, descubrimos algunos problemas al integrarlo todo con Maven:

  • El módulo Spring Cloud Sleuth Autoconfigure aún se encuentra en una versión preliminar.
  • El módulo Spring Cloud Sleuth Autoconfigure depende de una versión alfa obsoleta de opentelemetry-instrumentation-api. Actualmente no hay ninguna versión 1.x reciente y no alfa de esta biblioteca.
  • El proyecto debe obtener el modelo de objetos del proyecto (POM) principal spring-cloud-build de los repositorios de instantáneas de Spring debido a la forma en que Spring Cloud Sleuth codifica sus referencias de dependencias para las versiones de hito.

Esto complicó un poco la definición de nuestro proyecto Maven, ya que tuvimos que hacer que Maven obtuviera recursos tanto de los repositorios de Spring como de Maven Central, lo que indicaba claramente lo incipiente que era la compatibilidad con OpenTelemetry en Spring Cloud. Aun así, seguimos adelante y creamos un módulo común de telemetría para configurar el rastreo distribuido mediante Spring Cloud Sleuth y OpenTelemetry, junto con diversas funciones auxiliares y extensiones relacionadas con la telemetría.

En el módulo común de telemetría, ampliamos la funcionalidad de rastreo que ofrecen las bibliotecas Spring Cloud Sleuth y OpenTelemetry mediante:

  • Compatibles con Spring: clases de Autoconfiguration classes que configuran el seguimiento y las funcionalidades ampliadas del proyecto, y cargan atributos adicionales de recursos de seguimiento.
  • Implementaciones NoOp de interfaces, para que podamos deshabilitar el seguimiento durante el arranque inyectando instancias NoOp en todas las interfaces de Spring Cloud Sleuth.
  • Un interceptor de nomenclatura de trazas para normalizar los nombres de las trazas.
  • Un controlador de errores que registra los errores mediante slf4j y el seguimiento de Spring Cloud Sleuth.
  • Una implementación mejorada de los atributos de rastreo que codifica información adicional en cada traza emitida, como la versión del servicio, el ID de la instancia del servicio, el ID de la máquina, el nombre del pod, el ID del contenedor, el nombre del contenedor y el nombre del espacio de nombres.
  • Un inspector de sentencias con trazabilidad que inserta identificadores de traza en los comentarios que preceden a las sentencias SQL emitidas por Hibernate. Al parecer, ahora esto se puede hacer con SQLCommenter, pero todavía no hemos migrado a esta herramienta.

Además, implementamos un cliente HTTP compatible con Spring basado en Apache HTTP Client, ya que queríamos disponer de más métricas y opciones de personalización al realizar llamadas HTTP entre servicios. En esta implementación, los identificadores de traza y de segmento se envían como cabeceras al llamar a servicios dependientes, lo que permite incluirlos en los resultados del seguimiento. Asimismo, esta implementación proporciona métricas del grupo de conexiones HTTP que OpenTelemetry agrega.

En definitiva, integrar el seguimiento con Spring Cloud Sleuth y OpenTelemetry fue una tarea ardua, pero creemos que mereció la pena. Esperamos que este proyecto y esta publicación sirvan de guía a quienes quieran seguir este camino.

Seguimiento distribuido para NGINX

Para obtener trazas que conectaran todos los servicios durante todo el ciclo de vida de una solicitud, tuvimos que integrar OpenTelemetry en NGINX. Para ello, utilizamos el módulo de OpenTelemetry para NGINX (aún en fase beta). Como previmos que podría resultar difícil obtener binarios funcionales del módulo que fueran compatibles con todas las versiones de NGINX, creamos un repositorio de GitHub de imágenes de contenedor que incorporan módulos de NGINX no compatibles oficialmente. Ejecutamos compilaciones nocturnas y distribuimos el binario del módulo mediante imágenes de Docker desde las que resulta fácil importarlo.

Todavía no hemos integrado este proceso en el proceso de compilación de NGINX Ingress Controller del proyecto MARA, pero tenemos previsto hacerlo pronto.

Implementación de la recopilación de métricas

Tras completar la integración del seguimiento con OpenTelemetry, nos centramos en las métricas. No había métricas para nuestras aplicaciones basadas en Python, por lo que decidimos posponer su incorporación por el momento. En cuanto a las aplicaciones Java, el código fuente original de Bank of Anthos, que utiliza Micrometer junto con Stackdriver de Google Cloud, admite métricas. Sin embargo, eliminamos ese código de Bank of Sirius tras crear una bifurcación de Bank of Anthos, ya que no nos permitía configurar un backend de métricas. Aun así, el hecho de que ya hubiera puntos de instrumentación para métricas evidenciaba la necesidad de una integración adecuada de estas.

Para encontrar una solución configurable y pragmática, primero analizamos la compatibilidad con métricas de las bibliotecas Java de OpenTelemetry y de Micrometer. Al buscar comparaciones entre ambas tecnologías, encontramos varios resultados que enumeraban las carencias de OpenTelemetry cuando se utiliza como API de métricas en la JVM, aunque las métricas de OpenTelemetry aún se encontraban en fase alfa en el momento de redactar este texto. Micrometer es una capa de abstracción de métricas consolidada para la JVM, similar a slf4j, ya que proporciona una API común que actúa como interfaz para una implementación de métricas configurable, en lugar de ser una implementación de métricas en sí misma. Curiosamente, es la API de métricas predeterminada de Spring.

En ese momento, estábamos sopesando los siguientes hechos:

  • OpenTelemetry Collector puede recopilar métricas de prácticamente cualquier fuente, incluidas Prometheus, StatsD y el protocolo nativo OpenTelemetry Protocol (OTLP)
  • Micrometer también admite un gran número de backends de métricas, incluidos Prometheus y StatsD
  • El SDK de métricas de OpenTelemetry para la JVM permite enviar métricas mediante OTLP

Tras realizar algunos experimentos, decidimos que el enfoque más pragmático era utilizar la fachada de Micrometer con una implementación de Prometheus como backend y configurar OpenTelemetry Collector para que utilizara la API de Prometheus a fin de obtener las métricas de la aplicación. Sabíamos, por numerosos artículos, que la ausencia de determinados tipos de métricas en OpenTelemetry puede causar problemas, pero nuestros casos de uso no necesitan esos tipos, por lo que la solución de compromiso era aceptable.

Descubrimos algo interesante sobre OpenTelemetry Collector: aunque lo habíamos configurado para recibir trazas mediante OTLP y métricas mediante la API de Prometheus, también se puede configurar para enviar ambos tipos de datos a un receptor de datos externo mediante OTLP o cualquier otro protocolo compatible. Esto nos permitió probar fácilmente nuestra aplicación con LightStep.

En general, programar métricas en Java fue bastante sencillo porque las escribimos de acuerdo con la API de Micrometer, para la que hay numerosos ejemplos y tutoriales disponibles. Probablemente, lo más difícil tanto para las métricas como para el rastreo fue configurar correctamente el grafo de dependencias de Maven en el archivo pom.xml de telemetry-common.

Implementación de la agregación de errores

El proyecto OpenTelemetry no contempla en sí mismo la agregación de errores entre sus objetivos, ni ofrece una implementación del etiquetado de errores tan elegante como la de soluciones como Sentry o Honeybadger.io. No obstante, decidimos utilizar OpenTelemetry para agregar errores a corto plazo en lugar de incorporar otra herramienta. Con una herramienta como Jaeger, podemos buscar error=true para encontrar todas las trazas que presentan algún error. Esto al menos nos permite hacernos una idea de los problemas que se producen con más frecuencia. En el futuro, podríamos plantearnos añadir una integración con Sentry.

Implementación de comprobaciones de estado e introspección en tiempo de ejecución

En el contexto de nuestra aplicación, las comprobaciones de estado permiten a Kubernetes saber si un servicio funciona correctamente o si ha completado su fase de inicio. Cuando el servicio no funciona correctamente, Kubernetes puede configurarse para finalizar o reiniciar instancias. En nuestra aplicación, decidimos no utilizar las comprobaciones de estado de OpenTelemetry porque consideramos que la documentación era insuficiente.

En su lugar, para los servicios de la JVM utilizamos un proyecto de Spring llamado «Spring Boot Actuator», que no solo proporciona endpoints de comprobación de estado, sino también endpoints de introspección en tiempo de ejecución y de volcado de memoria. Para los servicios de Python, utilizamos el «módulo Flask Management Endpoints», que ofrece un subconjunto de las funcionalidades de Spring Boot Actuator. Actualmente, solo proporciona información personalizable sobre la aplicación y comprobaciones de estado.

Spring Boot Actuator se integra con la JVM y Spring para proporcionar endpoints de introspección, monitorización y comprobación del estado. Además, ofrece un marco para añadir información personalizada a los datos predeterminados que presenta en sus endpoints. Estos endpoints permiten inspeccionar en tiempo de ejecución aspectos como el estado de la caché, el entorno de ejecución, las migraciones de bases de datos, las comprobaciones del estado, la información personalizable de la aplicación, las métricas, las tareas periódicas, el estado de las sesiones HTTP y los volcados de hilos.

Los endpoints de comprobación de estado implementados por Spring Boot Actuator tienen una configuración modular, de modo que el estado de un servicio puede componerse de varias comprobaciones individuales clasificadas como de actividad o de disponibilidad. También hay disponible una comprobación de estado completa que muestra todos los módulos de comprobación y que suele tener un aspecto como este.

Los endpoints informativos se definen en un documento JSON como un único objeto JSON de alto nivel y una serie de claves y valores jerárquicos. Por lo general, el documento especifica el nombre y la versión del servicio, la arquitectura, el nombre del host, la información del sistema operativo, el ID del proceso, el nombre del ejecutable y datos sobre el host, como un ID de máquina o un ID de servicio único.

Implementación de volcados de memoria dinámica y de núcleo

Quizá recuerde por la tabla de Comparación de las funcionalidades de las herramientas con la lista de requisitos deseados que ninguna de las herramientas admite la introspección en tiempo de ejecución ni los volcados de memoria dinámica o del núcleo. Sin embargo, Spring, el framework subyacente que utilizamos, admite ambas funciones, aunque integrar las funciones de observabilidad en la aplicación requirió cierto trabajo. Como se detalla en la sección anterior, para la introspección en tiempo de ejecución utilizamos un módulo de Python junto con Spring Boot Actuator.

Del mismo modo, para los volcados de memoria usamos los endpoints de volcado de hilos que proporciona Spring Boot Actuator, lo que nos permite disponer de parte de las funcionalidades que buscábamos. No podemos obtener volcados de núcleo bajo demanda ni volcados de memoria de la JVM con el nivel de detalle ideal, pero conseguimos parte de la funcionalidad deseada con poco esfuerzo adicional. Lamentablemente, los volcados de núcleo de los servicios de Python requerirán bastante trabajo adicional, que hemos pospuesto para más adelante.

Resumen

Después de mucho llorar y cuestionarnos nuestras decisiones vitales, hemos acabado decantándonos por las siguientes tecnologías para la observabilidad en MARA (en lo sucesivo, «OTel» significa OpenTelemetry):

  • Registro (para todos los contenedores) – Filebeat → Elasticsearch / Kibana
  • Trazabilidad distribuida
    • Java – Spring Cloud Sleuth → exportador de Spring Cloud Sleuth para OTel → OTel Collector → exportadores conectables como Jaeger, Lightstep, Splunk, etc.
    • Python – Bibliotecas de OTel para Python → OTel Collector → almacenamiento intercambiable
    • NGINX y NGINX Plus (NGINX Ingress Controller aún no es compatible) – módulo OTel de NGINX → OTel Collector → exportador conectable
  • Recopilación de métricas
    • Java – Micrometer a través de Spring → exportador de Prometheus → OTel Collector
    • Python – Aún no se ha implementado
    • Python WSGI – GUnicorn StatsD → Prometheus (mediante StatsD / ServiceMonitor)
    • NGINX – endpoint de Prometheus → Prometheus (mediante ServiceMonitor)
  • Agregación de errores – Trazas distribuidas de OTel → exportador configurable → función de búsqueda del exportador para encontrar trazas marcadas con error
  • Comprobaciones de estado
    • Java – Spring Boot Actuator → Kubernetes
    • Python – Módulo Flask Management Endpoints → Kubernetes
  • Introspección en tiempo de ejecución
    • Java – Spring Boot Actuator
    • Python – módulo Flask Management Endpoints
  • Volcados de memoria dinámica/del núcleo
    • Java – Compatibilidad con volcados de hilos mediante Spring Boot Actuator
    • Python – Aún no es compatible

Esta implementación refleja el estado actual en un momento concreto. Sin duda, cambiará y evolucionará a medida que avance el desarrollo. Próximamente, someteremos la aplicación a exhaustivas pruebas de carga. Esperamos aprender mucho sobre las carencias de nuestro enfoque de observabilidad y añadir nuevas funciones en este ámbito.

Prueba la arquitectura de referencia para aplicaciones modernas y la aplicación de ejemplo (Bank of Sirius). Si tienes ideas sobre cómo podemos mejorar, tus contribuciones serán bienvenidas en nuestro repositorio de GitHub.

Publicaciones relacionadas

Esta publicación forma parte de una serie. A medida que vayamos incorporando nuevas funcionalidades a MARA, publicaremos todos los detalles en el blog:


Compartir

Artículos relacionados del blog

Únete a F5 NGINX en AppWorld 2024
NGINX | 04/01/2024

Únete a F5 NGINX en AppWorld 2024

Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
NGINX | 26/09/2023

Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source

La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.

Exposición de APIs en Kubernetes
NGINX | 10/03/2022

Exposición de APIs en Kubernetes

La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
NGINX | 23/08/2021

NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto

Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.

Presentamos NGINX Plus R22
NGINX | 09/06/2020

Presentamos NGINX Plus R22

NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.

Presentamos NGINX Plus R17
NGINX | 11/12/2018

Presentamos NGINX Plus R17

NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.