Rastreo y monitoreo de Istio: microservicios y el principio de incertidumbre

El principio de incertidumbre de Heisenberg establece que es imposible medir simultáneamente la posición de un objeto y su velocidad. Si un objeto se mueve, entonces no tiene ubicación. Y si la ubicación es, significa que no tiene velocidad.



En cuanto a los microservicios en la plataforma Red Hat OpenShift (y ejecutar Kubernetes), gracias al software de código abierto correspondiente, pueden informar simultáneamente tanto su rendimiento como su estado. Por supuesto, esto no refuta el viejo Heisenberg, pero elimina la incertidumbre cuando se trabaja con aplicaciones en la nube. Istio facilita la organización del seguimiento (rastreo) y el monitoreo de dichas aplicaciones para mantener todo bajo control.

Definir terminología


Por rastreo nos referimos a la actividad del sistema de registro. Suena bastante general, pero de hecho, una de las reglas principales aquí es volcar los datos de rastreo en el almacenamiento adecuado sin preocuparse por formatearlos. Y todo el trabajo de búsqueda y análisis de datos se confía a sus consumidores. Istio utiliza el sistema de rastreo Jaeger, que implementa el modelo de datos OpenTracing.

Por trazas (Traces, y la palabra "trazas" se usa aquí en el significado de "trazas", como, por ejemplo, en un examen balístico) nos referiremos a datos que describen completamente el paso de una solicitud o unidad de trabajo, como dicen, "desde y hacia". Por ejemplo, todo lo que sucede desde el momento en que el usuario presiona un botón en una página web hasta el momento en que se devuelven los datos, incluidos todos los microservicios involucrados en esto. Podemos decir que una traza describe completamente (o simula) el paso de la solicitud de un lado a otro. En la interfaz de Jaeger, las pistas se descomponen en componentes a lo largo del eje de tiempo, como la forma en que una cadena se puede descomponer en enlaces separados. Solo en lugar de enlaces, la pista consta de los llamados tramos.

El intervalo es el intervalo desde el comienzo de una unidad de trabajo hasta su finalización. Continuando con la analogía, podemos decir que cada tramo es un eslabón separado en la cadena. Un lapso puede o no tener uno o más tramos de niños. Como resultado, el tramo de nivel superior (tramo raíz) tendrá la misma duración total que la traza a la que pertenece.

El monitoreo es, de hecho, la simple observación de su sistema: a través de los ojos, a través de una interfaz de usuario o mediante la automatización. El monitoreo se basa en datos de rastreo. En Istio, el monitoreo se implementa utilizando las herramientas de Prometheus y tiene una IU correspondiente. Prometheus admite la supervisión automática mediante alertas y alertas de administradores de alertas.

Deja las mellas


Para que el rastreo sea posible, la aplicación debe crear una colección de tramos. Luego deben exportarse a Jaeger, para que él, a su vez, cree una representación visual de la traza. Entre otras cosas, estos tramos marcan el nombre de la operación, así como las marcas de tiempo de su inicio y finalización. Los tramos se envían reenviando encabezados Jaeger para solicitudes HTTP de solicitudes entrantes a solicitudes salientes. Dependiendo del lenguaje de programación utilizado, esto puede requerir una ligera modificación del código fuente de la aplicación. El siguiente es un ejemplo de código Java (cuando se usa el marco Spring Boot) que agrega encabezados B3 (estilo Zipkin) a su solicitud en la clase de configuración Spring:


Se utilizan las siguientes configuraciones de encabezado:


Si usa Java, puede dejar el código intacto, solo agregue algunas líneas al archivo POM de Maven y configure las variables de entorno. Estas son las líneas que debe agregar al archivo POM.XML para implementar el Resoludor de seguimiento de Jaeger:


Y las variables de entorno correspondientes se establecen en el Dockerfile:


Eso es todo, ahora está todo configurado y nuestros microservicios comenzarán a generar datos de rastreo.

Nos fijamos en términos generales


Istio incluye un panel de control simple basado en Grafana. Cuando todo está configurado y ejecutándose en la plataforma Red Hat OpenShift PaaS (en nuestro ejemplo, Red Hat OpenShift y Kubernetes se implementan en minishift), este panel se inicia con el siguiente comando:

open "$(minishift openshift service grafana -u)/d/1/istio-dashboard?refresh=5⩝Id=1" 

El panel Grafana le permite evaluar rápidamente el sistema. Un fragmento de este panel se muestra en la siguiente figura:


Aquí puede ver que el cliente de microservicio llama a la preferencia de microservicio v1, y que a su vez llama a la recomendación de microservicios v1 y v2. El panel Grafana tiene un bloque Dashboard Row para métricas de alto nivel, como el número total de solicitudes (Volumen de solicitud global), porcentaje de solicitudes exitosas (tasas de éxito), errores 4xx. Además, hay una vista de malla de servidor con gráficos para cada servicio y un bloque de fila de servicios para ver información detallada de cada contenedor para cada servicio.

Ahora cava más profundo


Con un seguimiento configurado correctamente, Istio, como se dice, listo para usar le permite profundizar en el análisis del rendimiento del sistema. En la interfaz de usuario de Jaeger, puede ver los rastros y ver hasta dónde llegan, así como localizar visualmente los cuellos de botella de rendimiento. Cuando use Red Hat OpenShift en la plataforma minishift, inicie la interfaz de usuario de Jaeger con el siguiente comando:

 minishift openshift service jaeger-query --in-browser 


Lo que se puede decir sobre el rastro en esta pantalla:

  • Se divide en 7 tramos.
  • El tiempo total de ejecución es de 6,99 ms.
  • La recomendación de microservicio, que es la última en la cadena, tarda 0,69 ms.

Los diagramas de este tipo le permiten descubrir rápidamente una situación en la que el rendimiento de todo el sistema sufre debido a un solo servicio que funciona mal.

Ahora, compliquemos la tarea y lancemos dos instancias del microservicio de recomendaciones: v2 con la escala oc --replicas = 2 implementación / recomendación-v2. Aquí están las vainas que tendremos después de esto:


Si ahora volvemos a Jaeger e implementamos el intervalo para el servicio de recomendación, veremos a qué solicitudes de pod se enrutan. Por lo tanto, podemos localizar fácilmente los frenos en el nivel de pod específico. Deberías mirar el campo node_id:


Donde y como va todo


Ahora vamos a la interfaz de Prometheus y, como es de esperar, vemos que las solicitudes entre la segunda y la primera versión del servicio de recomendaciones se dividen en una proporción de 2: 1, estrictamente por el número de unidades de trabajo. Además, este gráfico cambiará dinámicamente al escalar los pods hacia arriba y hacia abajo, lo que será especialmente útil con Canary Deployment (examinaremos este esquema de implementación con más detalle la próxima vez).


Es solo el comienzo


De hecho, hoy, como dicen, solo tocamos un depósito de información útil sobre Jaeger, Grafana y Prometeo. En general, este era nuestro objetivo: guiarlo en la dirección correcta y abrir las perspectivas de Istio.

Y recuerde, todo esto ya está integrado en Istio. Cuando se utilizan ciertos lenguajes de programación (por ejemplo, Java) y frameworks (por ejemplo, Spring Boot), todo esto se puede realizar sin tocar completamente el código de la aplicación. Sí, el código tendrá que modificarse ligeramente si usa otros idiomas, principalmente Nodejs o C #. Pero dado que la trazabilidad (leer, "rastreo") es uno de los requisitos previos para crear sistemas de nube confiables, en cualquier caso, tendrá que editar el código, ya sea que tenga Istio o no. Entonces, ¿por qué no gastar el esfuerzo de manera más rentable?

Al menos para responder siempre a las preguntas “¿dónde?” Y “¿qué tan rápido?” Con 100% de certeza.

Ingeniería del caos en Istio: fue concebido


La capacidad de romper cosas ayuda a garantizar que no se rompan


Las pruebas de software no solo son complicadas, sino también importantes. Al mismo tiempo, probar la corrección (por ejemplo, si una función devuelve el resultado correcto) es una cosa, y probar en una red poco confiable es una tarea completamente diferente (a menudo se cree que la red siempre funciona sin fallas, y esta es la primera de las ocho ideas erróneas sobre la distribución informática). Una de las dificultades para resolver este problema es cómo simular fallas en el sistema o introducirlas intencionalmente realizando la llamada inyección de falla. Esto se puede hacer modificando el código fuente de la aplicación en sí. Pero entonces no probará su código original, sino su versión, que simula específicamente fallas. Como resultado, corre el riesgo de caer en un abrazo fatal de la inyección de fallas y colisionar con las bolsas de seguridad, fallas que desaparecen cuando intenta detectarlas.

Y ahora mostraremos cómo Istio ayuda a hacer frente a estas dificultades uno-dos.

Cómo se ve cuando todo está bien


Considere el siguiente escenario: tenemos dos pods para nuestro microservicio de recomendaciones, que tomamos del tutorial de Istio. Un pod está marcado como v1 y el otro como v2. Como puede ver, mientras todo funciona bien:


(Por cierto, el número de la derecha es solo un contador de llamadas para cada pod)

Pero no necesitamos esto, ¿verdad? Bueno, intentemos romper todo sin tocar el código fuente.

Organizamos interrupciones en el trabajo del microservicio.


A continuación se muestra el archivo yaml para la regla de enrutamiento Istio, que en la mitad de los casos fallará (error del servidor 503):


Tenga en cuenta que prescribimos explícitamente que en la mitad de los casos se debe devolver el error 503.

Y aquí hay una captura de pantalla del comando curl lanzado en el bucle después de activar esta regla para simular fallas. Como puede ver, la mitad de las solicitudes devuelve el error 503, e independientemente de qué pod - v1 o v2 - van a:


Para restaurar la operación normal, es suficiente eliminar esta regla, en nuestro caso, el comando tutorial istioctl delete routerule Recomendacion-503 -n. Aquí Tutorial es el nombre del proyecto Red Hat OpenShift que ejecuta nuestro tutorial Istio.

Hacer retrasos artificiales


Los errores artificiales 503 ayudan a probar la tolerancia a fallas del sistema, pero la capacidad de predecir y manejar demoras debería impresionarlo aún más. Y los retrasos en la vida real ocurren con más frecuencia que los fracasos. Un microservicio de ejecución lenta es el veneno que sufre todo el sistema. Gracias a Istio, puede probar el código relacionado con el procesamiento diferido sin cambiarlo en absoluto. Para empezar, mostraremos cómo hacerlo en caso de retrasos en la red introducidos artificialmente.

Tenga en cuenta que después de tales pruebas, es posible que necesite (o desee) refinar su código. La buena noticia es que, en este caso, actuará de manera proactiva, no reactiva. Así es como se debe construir el ciclo de desarrollo: coding-testing-feedback-coding-testing ...

Así es como se ve la regla ... ¿Aunque sabes qué? Istio es tan simple, y este archivo yaml es tan claro que todo en este ejemplo habla por sí mismo, solo eche un vistazo:


En la mitad de los casos, tendremos un retraso de 7 segundos. Y esto no es lo mismo que si insertáramos el comando de suspensión en el código fuente, ya que Istio realmente retrasa la solicitud durante 7 segundos. Dado que Istio admite el rastreo de Jaeger, este retraso es excelente en la interfaz de usuario sesgada de Jaeger, como se muestra en la captura de pantalla a continuación. Preste atención a la solicitud larga en la esquina superior derecha del diagrama; su duración es de 7.02 segundos:


Este escenario le permite probar el código en condiciones de latencia de red. Y está claro que al eliminar esta regla, eliminaremos el retraso artificial. Repetimos, pero nuevamente hicimos todo esto sin tocar el código fuente.

No retrocedas y no te rindas


Otra característica de Istio que es útil para la ingeniería del caos son las llamadas repetidas al servicio un número específico de veces. El punto aquí es no dejar de intentarlo cuando la primera solicitud finaliza con el error 503, y luego, tal vez, por enésima vez, tenemos suerte. Tal vez el servicio simplemente permanezca por un corto tiempo por una razón u otra. Sí, esta razón debe desenterrarse y eliminarse. Pero esto es más tarde, pero por ahora intentemos que el sistema continúe funcionando.

Entonces, queremos que el servicio dé un error 503 de vez en cuando, y después de eso, Istio intentará contactarlo nuevamente. Y aquí claramente necesitamos una forma de generar el error 503, sin tocar el código en sí ...

Deja de esperar! Acabamos de hacerlo.

Este archivo hará que el servicio de recomendación-v2 genere un error 503 en la mitad del caso:


Obviamente, parte de las solicitudes fallarán:


Y ahora usaremos la función Retry Istio:


Esta regla de enrutamiento realiza tres reintentos con un intervalo de dos segundos y debería reducir (e idealmente eliminar completamente del radar) los errores 503:


Resumimos: lo hicimos para que Istio, en primer lugar, generara un error 503 para la mitad de las solicitudes. Y en segundo lugar, el mismo Istio hace tres intentos de volver a conectarse al servicio si se produce un error 503. Como resultado, todo funciona bien. Por lo tanto, utilizando la función Reintentar, cumplimos nuestra promesa de no dar marcha atrás y no rendirnos.

Y sí, lo volvimos a hacer sin tocar el código. Todo lo que necesitábamos eran dos reglas de enrutamiento de Istio:


Cómo no decepcionar a un usuario o siete no esperar


Y ahora damos la vuelta a la situación y consideramos el escenario en el que no tiene que retirarse o renunciar a un tiempo fijo. Y luego solo debe dejar de intentar procesar la solicitud para no obligar a todos a esperar a ningún servicio de frenado. En otras palabras, no protegeremos la posición perdida, sino que nos moveremos a la línea de reserva para no decepcionar al usuario del sitio y no forzarlo a languidecer en la ignorancia.

En Istio, puede configurar el tiempo de espera de la solicitud. Si el servicio excede este tiempo de espera, se devuelve el error 504 (Tiempo de espera de la puerta de enlace); nuevamente, todo esto se hace a través de la configuración de Istio. Pero tendremos que agregar el comando de suspensión al código fuente del servicio (y luego, por supuesto, ejecutar reconstruir y volver a implementar) para simular la operación lenta del servicio. Por desgracia, no funcionará de otra manera.

Entonces, insertamos una suspensión de tres segundos en el código de servicio de la recomendación v2, reconstruimos la imagen correspondiente e hicimos un modo de contenedor, y ahora agregaremos un tiempo de espera usando la siguiente regla de enrutamiento Istio:


La captura de pantalla anterior muestra que estamos tratando de contactar al servicio de recomendaciones si no recibimos una respuesta dentro de un segundo, es decir, antes de que ocurra el error 504. Después de aplicar esta regla de enrutamiento (y agregar una suspensión de tres segundos al código de servicio de recomendación) : v2), obtenemos esto:


Repetimos nuevamente, pero el tiempo de espera se puede configurar sin tocar el código fuente. Y una ventaja adicional aquí es que ahora puede modificar su código para que responda a un tiempo de espera, y es fácil probar estas mejoras con Istio.

Y ahora todos juntos


Hacer un poco de caos con Istio es una excelente manera de probar su código y la confiabilidad de su sistema como un todo. Los patrones de fallback, mamparo y disyuntor, mecanismos para crear fallas y demoras artificiales, y también llamadas repetidas y tiempos de espera serán muy útiles al crear sistemas de nube tolerantes a fallas. En combinación con Kubernetes y Red Hat OpenShift, estas herramientas lo ayudan a enfrentar con confianza el futuro.

Source: https://habr.com/ru/post/485136/


All Articles