Disyuntor Istio: desconecte los contenedores rotos

Las vacaciones terminaron y volvemos con nuestro segundo post en la serie Istio Service Mesh.



El tema de hoy es el disyuntor, que, traducido al ruso como electrotécnico, significa "disyuntor", coloquialmente - "disyuntor". Solo en Istio se desconecta esta máquina no de circuitos en cortocircuito o sobrecargados, sino de contenedores defectuosos.

Cómo debería funcionar idealmente


Cuando Kubernetes gestiona los microservicios, por ejemplo, como parte de la plataforma OpenShift, aumentan y disminuyen automáticamente según la carga. Dado que los microservicios funcionan en pods, puede haber varias instancias de microservicio en contenedores en un punto final, y Kubernetes enrutará las solicitudes y equilibrará la carga entre ellas. Y, idealmente, todo esto debería funcionar perfectamente.

Recordamos que los microservicios son pequeños y efímeros. La efímera, que aquí significa la simplicidad del origen y la desaparición, a menudo se subestima. El nacimiento y la muerte de la próxima instancia de microservicio en pod es bastante esperado, OpenShift y Kubernetes lo hacen bien, y todo funciona muy bien, pero nuevamente en teoría.

¿Cómo funciona realmente?


Ahora imagine que una instancia particular del microservicio, es decir, el contenedor, se ha vuelto inutilizable: o no responde (error 503) o, lo que es más desagradable, reacciona, pero demasiado lento. En otras palabras, silencia o no responde a las solicitudes, pero no lo elimina automáticamente del grupo. ¿Qué se debe hacer en este caso? Intenta de nuevo? ¿Eliminarlo del esquema de enrutamiento? ¿Y qué significa "demasiado lento": cuántos son estos números y quién los define? ¿Quizás solo darle un descanso e intentarlo más tarde? Si es así, ¿cuánto más tarde?

¿Qué es la eyección de la piscina en Istio?


Y aquí Istio viene al rescate con sus interruptores automáticos, que eliminan temporalmente los contenedores defectuosos del conjunto de recursos de enrutamiento y equilibrio de carga, implementando el procedimiento de expulsión del conjunto.

Utilizando una estrategia de detección de valores atípicos, Istio detecta las curvas de pod que se eliminan de la fila general y las elimina del grupo de recursos durante un tiempo determinado, llamado "ventana de suspensión".

Para mostrar cómo funciona esto en Kubernetes en la plataforma OpenShift, comenzamos con una captura de pantalla de los microservicios que normalmente funcionan del ejemplo en el repositorio de Demos de desarrolladores de Red Hat . Aquí tenemos dos pods, v1 y v2, en cada uno de los cuales funciona un contenedor. Cuando no se utilizan las reglas de enrutamiento de Istio, Kubernetes aplica de forma predeterminada un enrutamiento de ida y vuelta equilibrado uniformemente:


Preparándose para un choque


Antes de realizar la expulsión de la agrupación, debe crear una regla de enrutamiento Istio. Supongamos que queremos distribuir solicitudes entre pods con respecto a 50/50. Además, aumentaremos el número de contenedores v2 de uno a dos, de esta manera:

oc scale deployment recommendation-v2 --replicas=2 -n tutorial 

Ahora definimos una regla de enrutamiento para que el tráfico se distribuya entre los pods en una proporción de 50/50.


Y aquí está el resultado de esta regla:


Es posible quejarse de que en esta pantalla no es 50/50, sino 14: 9, pero con el tiempo la situación mejorará.

Arreglamos un fracaso


Y ahora deshabilitaremos uno de los dos contenedores v2 para que tengamos un contenedor saludable v1, un contenedor saludable v2 y un contenedor fallido v2:


Arreglar el accidente


Entonces, tenemos un contenedor defectuoso, y es hora de expulsar la piscina. Usando una configuración muy simple, excluiremos este contenedor fallido de cualquier esquema de enrutamiento durante 15 segundos con la expectativa de que volverá a un estado saludable (se reiniciará o restaurará el rendimiento). Así es como se ve esta configuración y los resultados de su trabajo:



Como puede ver, el contenedor v2 fallido ya no se usa al enrutar solicitudes, ya que se eliminó del grupo. Pero después de 15 segundos, volverá automáticamente a la piscina. En realidad, acabamos de mostrar cómo funciona la eyección de piscina.

Comienza a construir arquitectura


La expulsión de la piscina, combinada con las capacidades de monitoreo de Istio, le permite comenzar a construir un marco para reemplazar automáticamente los contenedores fallidos para reducir o incluso eliminar el tiempo de inactividad y los bloqueos.

La NASA tiene un lema de alto perfil: el fracaso no es una opción, escrito por el director de vuelo Gene Krantz . Se puede traducir al ruso como "La derrota no es una opción", y el punto aquí es que todo puede funcionar con suficiente voluntad. Sin embargo, en la vida real, las fallas no solo ocurren, son inevitables, en todas partes y en todo. ¿Y cómo afrontarlos en el caso de los microservicios? En nuestra opinión, es mejor confiar no en la fuerza de voluntad, sino en las capacidades de los contenedores, Kubernetes , Red Hat OpenShift e Istio .

Istio, como escribimos anteriormente, implementa el concepto de disyuntores, que se ha demostrado en el mundo físico. Y así como una máquina automática desconecta una parte problemática de un circuito, el disyuntor de software en Istio desconecta la conexión entre el flujo de solicitud y el contenedor del problema cuando algo está mal con el punto final, por ejemplo, cuando el servidor falla o comienza a disminuir la velocidad.

Además, en el segundo caso solo hay más problemas, ya que los frenos de un contenedor no solo causan una cascada de demoras en los servicios que acceden a él y, como resultado, reducen el rendimiento del sistema en su conjunto, sino que también provocan repetidas solicitudes al servicio que ya se está ejecutando lentamente, lo que solo exacerba la situación .

Disyuntor en teoría


Circuit Breaker es un proxy que controla el flujo de solicitudes al punto final. Cuando este punto deja de funcionar o, según la configuración, comienza a ralentizarse, el proxy se desconecta del contenedor. El tráfico se redirige a otros contenedores, bueno, solo por el equilibrio de carga. La conexión permanece abierta (abierta) para una ventana de suspensión dada, digamos, dos minutos, y luego se considera medio abierta (medio abierta). Intentar enviar la siguiente solicitud determina el estado posterior de la comunicación. Si todo está bien con el servicio, la conexión vuelve al estado operativo y nuevamente se cierra. Si todavía hay algo mal con el servicio, la conexión se abre y la ventana de suspensión se vuelve a habilitar. Así es como se ve el diagrama de estado del disyuntor simplificado:


Es importante señalar aquí que todo esto sucede a nivel de, por así decirlo, la arquitectura del sistema. Por lo tanto, en algún momento tendrá que enseñar a sus aplicaciones a trabajar con el disyuntor, por ejemplo, proporcionar un valor predeterminado en respuesta o, si es posible, ignorar la existencia del servicio. Para esto se usa un patrón de mamparo, pero está más allá del alcance de este artículo.

Disyuntor en la práctica


Por ejemplo, lanzaremos en OpenShift dos versiones de nuestro microservicio de recomendaciones. La versión 1 funcionará bien, pero en v2 construiremos un retraso para simular los frenos en el servidor. Para ver los resultados, use la herramienta de asedio :

 siege -r 2 -c 20 -v customer-tutorial.$(minishift ip).nip.io 


Todo parece funcionar, pero ¿a qué costo? A primera vista, tenemos una disponibilidad del 100%, pero eche un vistazo más de cerca: la duración máxima de la transacción es de hasta 12 segundos. Esto es claramente un cuello de botella y necesita ser bordado.

Para hacer esto, usaremos Istio para eliminar el acceso a contenedores lentos. Así es como se ve la configuración correspondiente usando el disyuntor:


La última línea con el parámetro httpMaxRequestsPerConnection indica que la conexión debería abrirse cuando se intenta crear una conexión más, la segunda, además de la existente. Dado que nuestro contenedor imita un servicio de frenado, tales situaciones ocurrirán periódicamente, y luego Istio devolverá un error 503, y esto es lo que mostrará el sitio:


OK, tenemos Circuit Breaker, ¿qué sigue?


Entonces, implementamos un apagado automático, sin tocar el código fuente de los propios servicios. Usando el interruptor de circuito y el procedimiento de expulsión del grupo descrito anteriormente, podemos quitar los contenedores de freno del grupo de recursos hasta que vuelvan a la normalidad y verificar su estado con la frecuencia especificada; en nuestro ejemplo, esto es dos minutos (parámetro sleepWindow).

Tenga en cuenta que la capacidad de la aplicación para responder al error 503 todavía se establece en el nivel de su código fuente. Existen muchas estrategias para trabajar con Circuit Breaker, que se aplican según la situación.

En la próxima publicación: hablaremos sobre el seguimiento y la supervisión, que ya están incorporados o se agregan fácilmente a Istio, así como sobre cómo introducir errores en el sistema intencionalmente.

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


All Articles