En el artículo de la semana pasada describimos las dificultades a las que se enfrentan los desarrolladores al trabajar con arquitecturas distribuidas o de microservicios, en muchas ocasiones, sin el conocimiento detallado necesario en las tecnologías de red subyacentes que hacen posible que las distintas piezas se comuniquen.
Como ya analizamos, los mayores retos no están relacionados con la lógica de negocio del software, sino con la forma en que los servicios interactúan entre sí. Para eso estamos los ingenieros de infraestructuras, haciendo que ambas tecnologías trabajen como una sola. En un ecosistema cloud-native como Kubernetes, estos desafíos pueden abordarse mediante la implementación de una malla de servicios o service mesh.
Service mesh y microservicios
Un service mesh se define como un sistema distribuido para abordar la problemática, a nivel de red, de los microservicios de manera integrada.
El sistema completo proporciona funciones complementarias a Kubernetes. Está construido sobre la base de una capa dedicada que controla todas las interacciones de servicio en el orquestador. La capa generalmente se compone de servidores proxy de red desplegados junto al servicio, sin que este lo sepa.
El objetivo de implementar una malla de servicios es tener una plataforma integrada que pueda monitorizar activamente todo el tráfico de los servicios. Al hacerlo, un service mesh puede abordar las preocupaciones relacionadas con la tolerancia a fallos, la seguridad del servicio y el monitoreo de aplicaciones.
Esta herramienta proporciona una nueva forma no intrusiva de implementar comunicaciones de manera eficiente. En comparación con los frameworks específicos de los lenguajes, un service mesh aborda los problemas fuera de los servicios.
Estos sistemas son independientes del protocolo y operan en la capa 5 (sesión). De esta manera, se pueden integrar en un entorno políglota. Dicha abstracción permite a los desarrolladores centrarse en la lógica de negocio de sus aplicaciones y permite a los ingenieros de sistemas operar la infraestructura de manera eficiente. Esta es una situación win-win para ambos. En general, una malla de servicios aborda las preocupaciones sobre estos desafíos y agrega los siguientes beneficios:
- Control del tráfico.
- Seguridad.
- Analítica del flujo de las operaciones.
Los microservicios en un service mesh logran esto al reenviar cabeceras de seguimiento. De esta forma, el rastreo distribuido puede ayudar a visualizar las dependencias entre servicios. Una malla de servicio también captura métricas en torno a los volúmenes de solicitud y las tasas de fallo.
Otro aspecto importante es el manejo de logs de servicio. En una aplicación tradicional, a menudo hay un archivo de log que registra todo. En una arquitectura de microservicios, donde tenemos una serie de ficheros de log, necesitamos buscarlos todos para comprender el comportamiento de cualquier flujo. Una malla de servicios proporciona logs centralizados y paneles gráficos construidos sobre logs.
Malla de servicios en sistemas distribuidos
Asumiendo que existen los problemas descritos por James Glosling, en los sistemas distribuidos, ¿cómo debemos atacarlos y en qué nos puede ayudar un service mesh?
- La red no es robusta ni confiable. Como ingenieros o arquitectos de software necesitamos estar preparados para lidiar con estos escenarios, introduciendo suficiente redundancia en el sistema en el lado del servidor, pero también en el lado del cliente se necesita añadir mecanismos de reintentos para poder manejar problemas de red transitorios.
- La latencia es alta. Patrones como circuit breaker tienen como objetivo manejar escenarios de latencias, encapsulando la llamada a un servicio remoto en un objeto que realiza un seguimiento de fallos, de tal forma que, si existen fallos, no se invocará más al servicio externo, y se devuelve instantáneamente un error al cliente. Si no se tienen en cuenta este tipo de consideraciones, estos fallos pueden tener un efecto cascada en el ecosistema completo.
- El ancho de banda es finito. Para superar situaciones como las del crecimiento de servicios, se hace necesario que las aplicaciones tengan un mecanismo de cuotas de alojamiento y trazabilidad de su consumo. Un crecimiento de microservicios también puede crear problemas de saturación en los balanceadores de carga y así degradar su rendimiento. Insertar balanceo de carga en el lado del cliente suele ser un buen enfoque para afrontar situaciones similares.
- La red no es segura. En arquitecturas de microservicios, cada uno de los equipos de desarrollo debe responsabilizarse de la seguridad. La comunicación entre microservicios necesita ser controlada. La autenticación a nivel de servicio es imprescindible para filtrar conexiones desconocidas.
- La topología cambia. Como ya comentamos, un simple escalado horizontal en un servicio puede cambiar flujos de tráfico e insertar fallos inesperados. Un sistema de descubrimiento de servicios puede solucionar este tipo de problemas en gran medida.
- Hay varios administradores del sistema. Para tener éxito en este aspecto se necesita un acceso basado en roles o RBAC.
- El coste de transporte no es cero. La transmisión de datos puede incurrir también en costes. Los datos deben ser serializados entre extremos. Protocolos como SOAP/XML son altamente ineficientes, JSON se considera mejor elección, pero protocolos binarios como buffers de protocolo, independientes del lenguaje han mejorado JSON. Considerando que el intercambio de información ocurre entre aplicaciones, es preferible usar un protocolo binario para el ecosistema completo.
- La red es heterogénea. Una malla de servicio nos permite desacoplar la infraestructura del código de la aplicación. También simplifica la topología de red subyacente, ya que la red solo proporciona la conexión física. Todos los firewalls, balanceadores de carga y subredes se pueden eliminar, dado que no quieren controlar ninguna interacción de servicio.