
El mundo no se detiene. El progreso crea nuevos desafíos tecnológicos. De acuerdo con los requisitos cambiantes, la arquitectura de los sistemas de información también debe evolucionar. Hoy hablaremos sobre arquitectura orientada a eventos, competitividad, concurrencia, asincronía y cómo vivir pacíficamente con todo esto en Erlang.
Introduccion
Dependiendo del tamaño del sistema que se está diseñando y los requisitos para él, nosotros, los desarrolladores, elegimos el método de intercambio de información en el sistema. En la mayoría de los casos, para organizar la interacción de los servicios, una opción de trabajo puede ser un esquema con un corredor, por ejemplo, basado en RabbitMQ o kafka. Pero a veces el flujo de eventos, el SLA y el nivel de control sobre el sistema son tales que los mensajes listos no son adecuados para nosotros. Por supuesto, puede complicar un poco el sistema asumiendo la responsabilidad de la capa de transporte y la formación del clúster, por ejemplo, usando ZeroMQ o nanomsg. Pero si el sistema tiene suficiente ancho de banda y capacidades de un clúster Erlang estándar, entonces la cuestión de introducir una entidad adicional requiere un estudio detallado y una justificación económica.
El tema de las aplicaciones distribuidas reactivas es bastante extenso. Para mantener el formato del artículo, el tema de la discusión de hoy serán solo entornos homogéneos construidos sobre la base de Erlang / Elixir. El ecosistema Erlang / OTP permite una arquitectura reactiva de bajo costo. Pero en cualquier caso, necesitamos una capa de mensajería.
Base teórica
El diseño comienza con la definición de objetivos y limitaciones. El objetivo principal no está en el desarrollo para el desarrollo. Necesitamos obtener una herramienta segura y escalable sobre la base de la cual podamos crear y, lo que es más importante, desarrollar aplicaciones modernas en varios niveles: desde servidores de un solo servidor que atienden a una audiencia pequeña, que luego pueden convertirse en grupos de hasta 50-60 nodos, terminando con federaciones de grupos. Por lo tanto, el objetivo principal es maximizar las ganancias al reducir el costo de desarrollo y la propiedad del sistema final.
Hay 4 requisitos principales para el sistema final:
- Con orientación cotidiana.
El sistema siempre está listo para pasar por sí mismo un flujo de eventos y realizar las acciones necesarias; - Escalabilidad.
Los bloques individuales se pueden escalar tanto vertical como horizontalmente. Todo el sistema debería poder infinito crecimiento horizontal; - Sobre tolerancia a fallas.
Todos los niveles y todos los servicios deberían poder recuperarse automáticamente de las fallas; - Tiempo de respuesta garantizado.
El tiempo es valioso y los usuarios no deben esperar demasiado.
¿Recuerdas el viejo cuento de hadas sobre "El pequeño motor que podría", también conocido como "El motor que podría"? Para que el sistema diseñado emerja con éxito de la etapa de prototipo y sea progresivo, su base debe cumplir con los requisitos mínimos de SMOG .
Otra cosa se agrega a la mensajería como herramienta de infraestructura y base para todos los servicios: usabilidad para programadores.
Orientación de eventos
Para que una aplicación crezca de un solo servidor a un clúster, su arquitectura debe proporcionar una conectividad débil. El modelo asincrónico cumple con este requisito. En él, el remitente y el destinatario se encargan de la carga de información del mensaje y no se preocupan por la transmisión y el enrutamiento dentro del sistema.
Escalabilidad
La escalabilidad y el rendimiento del sistema están uno al lado del otro. Los componentes de la aplicación deben poder utilizar todos los recursos disponibles. Cuanto más eficientes podamos utilizar las capacidades y más óptimos nuestros métodos de procesamiento, menos gastaremos dinero en equipos.
Erlang crea un entorno altamente competitivo dentro de una sola máquina. El equilibrio entre concurrencia y concurrencia se puede establecer seleccionando el número de subprocesos del sistema operativo disponibles para Erlang VM y el número de planificadores que utilizan estos subprocesos.
Los procesos de Erlang no tienen un estado común y funcionan en modo sin bloqueo. Esto proporciona una latencia relativamente baja y un mayor ancho de banda que las aplicaciones tradicionales basadas en la sincronización de bloqueo. El planificador de Erlang se encarga de la distribución equitativa de CPU e IO, y la ausencia de bloqueos permite que la aplicación responda incluso en cargas pico o fallas.
A nivel de clúster, también existe un problema de reciclaje. Es importante que todas las máquinas del clúster estén cargadas de manera uniforme y la red no esté sobrecargada. Imagine una situación: el tráfico de usuarios llega a los balanceadores entrantes (haproxy, nginx, etc.), distribuyen las solicitudes de procesamiento de la manera más uniforme posible entre el conjunto de backends disponibles. Dentro del marco de la infraestructura de la aplicación, un servicio que implementa la interfaz requerida es solo el último tramo, y deberá solicitar una serie de otros servicios para responder a la solicitud inicial. Las consultas internas también requieren enrutamiento y equilibrio.
Para gestionar eficazmente los flujos de datos, la mensajería debe proporcionar a los desarrolladores una interfaz para controlar el enrutamiento y el equilibrio de carga. Gracias a esto, los desarrolladores podrán, utilizando patrones de microservicio (agregador, proxy, cadena, rama, etc.), resolver las tareas estándar y las que surgen raramente.
Desde una perspectiva empresarial, la escalabilidad es una de las herramientas de gestión de riesgos. Lo principal es satisfacer las demandas de los clientes mediante el uso óptimo del equipo:
- Con un aumento en la capacidad del equipo como resultado del progreso. No estará inactivo debido a imperfecciones de software. Erlang escala perfectamente verticalmente y siempre puede reciclar todos los núcleos de CPU y la memoria disponible;
- En entornos nublados, podemos controlar la cantidad de equipos en función de la carga actual o prevista y garantizar SLA.
Tolerancia a fallos
Considere dos axiomas: "Las fallas son inaceptables" y "Las fallas siempre lo serán". Para las empresas, la falla del software es la pérdida de dinero y, lo que es peor, la reputación. Al equilibrar las pérdidas potenciales y el costo de desarrollar software tolerante a fallas, a menudo puede encontrar un compromiso.
A corto plazo, la arquitectura con tolerancia a fallas ahorra dinero en la compra de soluciones de agrupación llave en mano. Son caros y también tienen errores.
A largo plazo, la arquitectura tolerante a fallas paga repetidamente los costos de su aplicación en todas las etapas de desarrollo.
La mensajería dentro de la base del código en la etapa de diseño le permite resolver en detalle la interacción de los componentes dentro del sistema. Esto simplifica la tarea de responder y gestionar fallas, ya que todos los componentes críticos manejan las fallas, y el sistema resultante sabe cómo volver automáticamente a la normalidad después de una falla por diseño.
Capacidad de respuesta
Independientemente de las fallas, la aplicación debe responder a las solicitudes y satisfacer los SLA. La realidad es que las personas no quieren esperar, por lo que el negocio debe adaptarse. Se espera que más aplicaciones sean altamente receptivas.
Las aplicaciones receptivas funcionan en modo cercano al tiempo real. Erlang VM funciona en modo suave en tiempo real. Para algunas áreas, como el intercambio comercial, la medicina, la gestión de equipos industriales, el modo en tiempo real es importante.
Los sistemas receptivos mejoran la experiencia de usuario y ayudan a las empresas.
Resultado preliminar
Al planear este artículo, quería compartir la experiencia de crear un agente de mensajería y construir sistemas complejos sobre la base. Pero la parte teórica y motivadora resultó ser bastante extensa.
En la segunda parte del artículo hablaré sobre los matices de la implementación de puntos de intercambio, plantillas de mensajería y su aplicación.
En la tercera parte, consideramos los problemas generales de organización de servicios, enrutamiento y equilibrio. Hablemos del lado práctico de la escalabilidad y la tolerancia a fallas de los sistemas.
El final de la primera parte.
Foto @lucabravo .