Cree una arquitectura escalable y resistente con microservicios dinámicos

Hola de nuevo. Como saben, en marzo, OTUS lanza un curso completamente nuevo sobre Arquitectura y Patrones de Diseño . Antes del comienzo del curso, se ha traducido una gran cantidad de material sobre la creación de una arquitectura escalable y resistente utilizando microservicios dinámicos. ¡Disfruta leyendo!




anotación


Una de las tendencias más importantes en la arquitectura industrial es el uso de microservicios en detrimento de las arquitecturas monolíticas que están perdiendo popularidad. Gracias a la arquitectura de la nube, la implementación de sistemas de microservicio es más productiva, flexible y rentable. Sea como fuere, muchas compañías ya han comenzado a moverse de un tipo de arquitectura a otra, pero esto todavía está en su infancia. En este artículo, resolvemos problemas derivados de la necesidad de desarrollar un sistema escalable y tolerante a fallas basado en microservicios. En nuestros experimentos, consideramos dos tipos de microservicios, simples y avanzados, y mostramos que la solución propuesta es innovadora en función de su comportamiento dinámico.

1. Introducción


En las últimas décadas, la historia de los lenguajes de programación y los paradigmas informáticos se ha caracterizado por una mayor atención a la distribución y modularización para mejorar la reutilización y la confiabilidad del código.

Era necesario aumentar la cantidad y la calidad del software [1]. Uno de los factores clave para aclarar los diversos desacuerdos asociados con el diseño innovador es la idoneidad del uso de diversas herramientas para el diseño y desarrollo de sistemas de software más avanzados [2]. Recientemente se demostró un gran éxito en este proceso mediante sistemas basados ​​en microservicios [3], que son un paradigma arquitectónico centrado en diversas aplicaciones (por ejemplo, para personas con discapacidad) [3]. Bajo los auspicios de microservicios, el interés por la arquitectura y el diseño está creciendo. Atributos de calidad (p. Ej., Escalabilidad, rendimiento y tolerancia a errores) o selección de modelo, como "contrato de servicio" [5] o API Gateway,ya no viola el principio YAGNI ("No lo va a necesitar" - "sufre errores de BDUF" ("Gran diseño por adelantado" - "Diseño a gran escala primero"). La principal pregunta de investigación que este artículo pretende responder es ¿cómo podemos desarrollar un sistema basado en microservicios con la misma simplicidad que un sistema monolítico? Y además, a partir del tema anterior, ¿cómo podemos crear un entorno que proporcione una distribución dinámica de la potencia informática entre los clientes? Nuestra hipótesis de investigación sugiere utilizar una arquitectura de sistema cliente-servidor que combine computación distribuida y microservicios para resolver estos problemas.La principal pregunta de investigación que este artículo pretende responder es ¿cómo podemos desarrollar un sistema basado en microservicios con la misma simplicidad que un sistema monolítico? Y además, a partir del tema anterior, ¿cómo podemos crear un entorno que proporcione una distribución dinámica de la potencia informática entre los clientes? Nuestra hipótesis de investigación sugiere utilizar una arquitectura de sistema cliente-servidor que combine computación distribuida y microservicios para resolver estos problemas.La principal pregunta de investigación que este artículo pretende responder es ¿cómo podemos desarrollar un sistema basado en microservicios con la misma simplicidad que un sistema monolítico? Y además, a partir del tema anterior, ¿cómo podemos crear un entorno que proporcione una distribución dinámica de la potencia informática entre los clientes? Nuestra hipótesis de investigación sugiere utilizar una arquitectura de sistema cliente-servidor que combine computación distribuida y microservicios para resolver estos problemas.¿Cuál proporciona una distribución dinámica de la potencia informática entre los clientes? Nuestra hipótesis de investigación sugiere utilizar una arquitectura de sistema cliente-servidor que combine computación distribuida y microservicios para resolver estos problemas.¿Cuál proporciona una distribución dinámica de la potencia informática entre los clientes? Nuestra hipótesis de investigación sugiere utilizar una arquitectura de sistema cliente-servidor que combine computación distribuida y microservicios para resolver estos problemas.

La estructura del documento es la siguiente: la sección 2 proporciona una breve descripción de la literatura actual que explica la importancia de los microservicios, incluidos dos servicios conocidos ofrecidos por Azure, y la sección 3 discute la arquitectura propuesta. La Sección 4 discute la evaluación de este sistema antes de sacar conclusiones en la última sección.

2. Revisión bibliográfica de microservicios


Gracias a la arquitectura de la nube, la implementación de sistemas de microservicio es más productiva, flexible y rentable [6]. Sin embargo, Zimmermann señala que los microservicios son un tema delicado que se está estudiando principalmente en la academia [7] y la industria. El término "microservicios" se discutió por primera vez en un seminario de arquitectos de software en Italia en mayo de 2011 para describir lo que los participantes vieron como un estilo arquitectónico común recientemente explorado por muchos de ellos. Un año después, el mismo grupo confirmó que el término "microservicios" es el nombre más apropiado. De hecho, los microservicios se desarrollaron como respuesta a problemas en aplicaciones monolíticas o arquitecturas orientadas a servicios que complican la escalabilidad, la complejidad y las dependencias de la aplicación que se está desarrollando.junto con el uso de mecanismos de comunicación livianos [8-9]. Dado que el monolito es una aplicación de software cuyos módulos no se pueden ejecutar de forma independiente, debemos considerar una solución basada en microservicios, ya que es la única capaz de ejecutar instrucciones independientes entre sí [10-11]. Los monolitos grandes se vuelven problemáticos de mantener con el tiempo y son difíciles de evaluar debido a su complejidad, pero la principal desventaja es que limitan la escalabilidad del producto. Otro problema es que no proporcionan tolerancia a fallas y no permiten que un componente individual del sistema funcione cuando otro componente no funciona, lo cual es posible en arquitecturas orientadas a microservicios.Dado que el monolito es una aplicación de software cuyos módulos no pueden ejecutarse independientemente, deberíamos considerar una solución basada en microservicios, ya que es la única capaz de ejecutar instrucciones independientes entre sí [10-11]. Los monolitos grandes se vuelven problemáticos de mantener con el tiempo y son difíciles de evaluar debido a su complejidad, pero la principal desventaja es que limitan la escalabilidad del producto. Otro problema es que no proporcionan tolerancia a fallas y no permiten que un componente individual del sistema funcione cuando otro componente no funciona, lo cual es posible en arquitecturas orientadas a microservicios.Dado que el monolito es una aplicación de software cuyos módulos no pueden ejecutarse independientemente, deberíamos considerar una solución basada en microservicios, ya que es la única capaz de ejecutar instrucciones independientes entre sí [10-11]. Los monolitos grandes se vuelven problemáticos de mantener con el tiempo y son difíciles de evaluar debido a su complejidad, pero la principal desventaja es que limitan la escalabilidad del producto. Otro problema es que no proporcionan tolerancia a fallas y no permiten que un componente individual del sistema funcione cuando otro componente no funciona, lo cual es posible en arquitecturas orientadas a microservicios.capaz de ejecutar instrucciones independientes entre sí [10-11]. Los monolitos grandes se vuelven problemáticos de mantener con el tiempo y son difíciles de evaluar debido a su complejidad, pero la principal desventaja es que limitan la escalabilidad del producto. Otro problema es que no proporcionan tolerancia a fallas y no permiten que un componente individual del sistema funcione cuando otro componente no funciona, lo cual es posible en arquitecturas orientadas a microservicios.capaz de ejecutar instrucciones independientes entre sí [10-11]. Los monolitos grandes se vuelven problemáticos de mantener con el tiempo y son difíciles de evaluar debido a su complejidad, pero la principal desventaja es que limitan la escalabilidad del producto. Otro problema es que no proporcionan tolerancia a fallas y no permiten que un componente individual del sistema funcione cuando otro componente no funciona, lo cual es posible en arquitecturas orientadas a microservicios.y no permiten que un componente individual del sistema funcione cuando otro componente no funciona, lo cual es posible en arquitecturas orientadas a microservicios.y no permiten que un componente individual del sistema funcione cuando otro componente no funciona, lo cual es posible en arquitecturas orientadas a microservicios.

En SOA (Service Oriented Architecture), los principales servicios se coordinan mediante dos métodos: orquestación (donde hay un microservicio central que enviará solicitudes a otros servicios y controlará todo el proceso enviando y recibiendo respuestas) y coreografía (que no implica ninguna centralización, pero cada servicio sabe de antemano lo que debe hacer) [1]. Como en el caso de las arquitecturas monolíticas y las arquitecturas SOA, el problema más difícil sigue siendo la partición del sistema en servicios [12]. Además, en ningún caso debe descuidar la cuestión de proporcionar información confidencial a través de la distribución incontrolada de servicios [13].

Nuestra arquitectura combina la informática distribuida con microservicios para crear un entorno que permita la distribución dinámica de la informática entre los clientes. Por computación distribuida, nos referimos a la disponibilidad de procesar y almacenar grandes cantidades de datos en la nube, que es un elemento clave en la industria moderna tanto dentro como fuera del campo de TI. Los sistemas de almacenamiento distribuido están diseñados para cumplir con los requisitos de aplicaciones distribuidas y computacionalmente avanzadas con amplia aplicabilidad, escalabilidad y alto rendimiento. Una solución bien conocida es MapReduce [14], que organiza los cálculos clasificando los servidores distribuidos, a la vez que administra varias tareas, todas las comunicaciones y la transferencia de datos entre partes del sistema,proporcionando redundancia y tolerancia a fallas.

Azure Batch es otro modelo de programación utilizado para ejecutar eficientemente aplicaciones computarizadas en modo paralelo o en gran escala, sin configuración manual o administración de infraestructura, con grupos más potentes de computación de alto rendimiento (HPC - computación de alto rendimiento) [15]. Para ilustrar estas ideas, permítanos recordarle SaaS (software como servicio) o aplicaciones cliente que necesitan una amplia ejecución [16]. De hecho, varias compañías de TI muestran un mayor interés en SaaS, están interesadas en reducir sus gastos operativos y, como resultado, en aumentar la flexibilidad de sus negocios [17]. Otro servicio ofrecido por los principales proveedores de servicios en la nube es Azure Functions,que permite el lanzamiento bajo demanda sin la necesidad de una provisión explícita o gestión de infraestructura [18].

También aumenta el interés de las aplicaciones en lanzar fácilmente pequeñas piezas de código o "funciones" en la nube. El creciente interés en Internet de las cosas (IoT) hace de Azure Functions [19] una excelente solución para el procesamiento de datos, la integración de sistemas y la creación de API y microservicios simples.

3. Metodología


El sistema estructuralmente propuesto se puede dividir en 3 áreas diferentes: (1) el cliente, que realizará las tareas asignadas por el servidor; (2) servidor: una interfaz con un cliente, el cerebro de las aplicaciones monolíticas; (3) un área de gestión de comunicación cliente-servidor que encapsula todos los detalles asociados con la transferencia de ejecución del servidor al cliente. Toda la información transmitida a través de la red entre el cliente y el servidor se cifra utilizando el algoritmo DES (Estándar de cifrado de datos), y la clave se cambia utilizando el protocolo Diffie-Hellman [20], que, aunque es vulnerable en ciertas condiciones, pero implementado en una variedad de soluciones de seguridad de Internet.

3.1. Arquitectura del sistema

Nuestro sistema se basa en gran medida en la arquitectura de los sistemas de microservicios dinámicos. La arquitectura toma como base el cliente-servidor, en el cual el servidor corresponde a un mayor número de clientes. Tanto el servidor como el cliente realizan microservicios web, el protocolo de comunicación es HTTP, el formato de datos es JSON. Esta arquitectura es útil para distribuir y redistribuir dinámicamente recursos entre clientes. Dicho modelo arquitectónico se utiliza para crear aplicaciones grandes, complejas y escalables horizontalmente que consisten en procesos pequeños, independientes y separados que interactúan entre sí mediante la API [21].

En la Fig. La Figura 1 muestra cómo un servidor distribuye paquetes de funcionalidad para sus clientes. Dependiendo del número de clientes, puede haber instrucciones que no se asignarán a ningún cliente, o el mismo conjunto de instrucciones asignadas a varios clientes.


Higo. 1. Distribución de servicios a clientes.

La arquitectura de la aplicación se creó utilizando el marco ASP.NET MVC de Microsoft. En la parte central, vemos microservicios de servidor en el servidor mismo, y a la izquierda y a la derecha hay muchos clientes esperando para iniciar tareas desde el servidor. El componente de servicio de orquestación proporciona, por un lado, comunicación entre el servidor y los clientes, enviando tareas a los clientes y, por otro lado, monitorea el estado de estas solicitudes.

Esta arquitectura permite que un microservicio llame a otro microservicio (por lo tanto, obtenemos un microservicio extendido (extendido)) o se llame entre sí, lo que puede conducir a una dependencia circular, que debe evitarse a nivel de usuario. El protocolo de comunicación cliente-servidor se lleva a cabo en los siguientes pasos:

  1. El cliente se conecta al servidor e inicia un protocolo de intercambio de claves. También los proporcionará al servidor y al puerto al que corresponderán.
  2. El servidor notifica al cliente la siguiente tarea a realizar (la tarea está representada por un par (microservicio, datos de entrada)).
  3. El cliente recibe el trabajo y luego notifica al servidor que la transferencia y la descarga se han completado con éxito o sin éxito.
  4. Tan pronto como se establece la conexión entre los dos objetos, el servidor envía los datos en formato JSON, encriptados usando DES, al cliente para su procesamiento.
  5. ( , ) JSON, DES.
  6. , .
  7. — .

Un caso especial de esta interacción es un escenario cuando un cliente realiza una tarea para cuyo resultado se requiere el resultado de otro cliente. Para este caso, se evaluaron dos posibilidades existentes: orquestación y coreografía.

En el caso de la coreografía, identificamos varios obstáculos: (a) el servidor tenía que enviar una lista de clientes disponibles para realizar una tarea externa al cliente, y mantener esta lista de valores actualizados a menudo resultaría en una mayor carga en la red de intercambio de información; (b) la comunicación entre los dos clientes era vulnerable a los ataques. Dos situaciones se resolvieron a través de la orquestación. De hecho, todo el cuidado de la gestión recae en el servidor, y los clientes son simplemente objetos simples con los que es fácil trabajar.

Para la opción de microservicios extendidos, las fases de interacción cliente-cliente serán las siguientes:

  1. . , . , DES.
  2. , , . , , , , . , ( . .).
  3. , ( ), , .
  4. .
  5. El cliente descifra el resultado con una contraseña de un solo uso y continúa la ejecución.

3.2. Aplicación

Para probar y evaluar esta arquitectura, implementamos varios microservicios a los que solicitamos lo que queríamos verificar a la vez.


Higo. 2. La interfaz.

En el primer experimento, utilizamos 3 microservicios de la siguiente manera: (1) un microservicio que realiza una operación matemática en dos números (usando LibraryMath), (2) un microservicio que nos dice si el número es positivo (MasterOfNumbers) y (3) un microservicio extendido, que llamará al primer microservicio cuando reciba dos números, y el resultado se enviará al segundo microservicio para extraer información sobre este número (UniverseOfSuperMath).

La Figura 2 muestra cómo obtenemos cálculos matemáticos utilizando los microservicios presentados. En el nivel de la interfaz, solo se muestra el resultado de una operación matemática, el resto de la información se puede ver como resultado de que el servidor recibe una llamada AJAX presionando la tecla igual (ambos resultados son positivos).

A continuación, consideraremos la funcionalidad principal de la aplicación, que se centra en lo que sucede cuando hay uno, dos o más clientes conectados. En la Figura 3 vemos cómo en nuestros experimentos lanzamos más clientes en la computadora local, utilizando diferentes puertos para cada uno de ellos.


Higo. 3. La interfaz.

Tenemos 6 campos: ClientToken: un token único asociado con cada cliente (cuando la llamada es local y tiene un valor localhost); Fecha: el momento en que se realizó la solicitud; IP y puerto = dirección IP del cliente y el puerto a través del cual se realiza la comunicación; Función: nombre de la función llamada; Éxito: una bandera booleana que indica el éxito de la llamada. Por ejemplo, notamos que en la primera llamada (h: 8:38:21 el cliente no está conectado al servidor, el proceso lo realiza el servidor). En la segunda llamada, observamos el comportamiento dinámico del sistema, una de las tareas que realiza uno de los clientes y las otras dos las realiza el servidor. Más específicamente, se llama UniverserOfSuperMath (localmente, el cliente no está disponible para esta tarea), que, a su vez, llama a otros dos microservicios, uno local y otro a través de un cliente delegado para usar una instrucción específica, etc.re.

Tolerancia a fallas
Otra funcionalidad que tomé en cuenta al crear esta arquitectura estaba relacionada con la tolerancia a fallas del sistema. Según el escenario anterior, podemos observar qué sucede si uno o más clientes eligen abandonar el sistema.

En la Figura 3 a la derecha, la llamada a las 8:46 demuestra este escenario. Los clientes en los puertos 8390 y 8827 tienen un problema local o de red o simplemente cierran la conexión al servidor, y el servidor no recibe una notificación a tiempo para eliminarlos de la lista. El servidor intentará contactar a los clientes y ejecutar comandos, pero si no responden de manera oportuna, el servidor asume sus tareas y devuelve el resultado solicitado. Para su confirmación, se solicitará nuevamente a los clientes después de un tiempo, y si continúan sin responder, serán eliminados de la lista de clientes disponibles. La próxima llamada (8:47) ya no solicitará inútilmente a clientes que ya no están disponibles, y el servidor realizará las tareas que los clientes omiten.

Ventajas y desventajas de la solución propuesta.

Las ventajas de esta arquitectura son obvias: los bajos costos de alojamiento, los microservicios ofrecidos en una red distribuida son dinámicos y escalables automáticamente (cuando los clientes también ofrecen potencia informática a medida que aumentan, la potencia informática del sistema aumenta).

Las limitaciones deben enfatizarse igualmente: cuando la curva de potencia informática no coincide con la curva de potencia del cliente. También tenemos una restricción sobre la capacidad de ejecutar esta aplicación en cualquier sistema operativo. Para hacer esto, decidimos convertir una solución asequible de .NET a Java. Pero esta solución tiene algunos inconvenientes con respecto a la solución original (Java ofrece una velocidad de procesamiento de datos menor y una transferencia de paquetes menos dinámica que la que tenemos en .NET). Actualmente estamos utilizando esta solución porque el .Net Core ofrecido por Microsoft para trabajar en varias plataformas aún no es una solución madura y no ofrece todas las funciones de la plataforma estándar .NET).

3.3. Componentes cliente-servidor

3.3.1. Cliente

En esta arquitectura, el cliente es una aplicación de escritorio de Windows Presentation Foundation (WPF) específicamente diseñada para comunicarse con el servidor y realizar diversas tareas recibidas de él. Dado que la aplicación es un archivo ejecutable que no requiere instalación, el sistema operativo debe funcionar con .Net Framework. Esencialmente, un microservicio web interactuará con otro microservicio web.

Primero, el cliente inicia el programador de tareas en un subproceso paralelo, que cada minuto intentará notificar al servidor de su presencia. Una tarea puede tomar dos estados: (1) o bien hay una tarea para ejecutar (la inicialización del paquete de código ya se ha completado) - en este caso solo notifica al servidor de su presencia; (2) o requiere inicialización con el servidor.

La inicialización con el servidor incluye, en primer lugar, una elección arbitraria de código y puerto que iniciará el servidor, que a su vez se le envía utilizando el protocolo de intercambio de claves Diffie-Hellman (IKE). Tan pronto como se establezca la conexión entre los dos objetos, el servidor notificará al cliente con un paquete de instrucciones para la instalación. La función principal del cliente es recibir un paquete de instrucciones del servidor, cargarlo en la memoria, procesar la información recibida del servidor y luego devolver el resultado obtenido al ejecutar este paquete de instrucciones. El primer paso realizado por el cliente es contactar al servidor para obtener un paquete de instrucciones. Este paquete de instrucciones viene como un archivo ZIP.

Antes de extraer este paquete, elimine el directorio anterior con instrucciones de la carpeta "proceso" (si existe), luego extraiga el nuevo contenido en esta carpeta y cárguelo en la memoria. La carga de memoria comienza una vez, independientemente de cuántas llamadas reciba el cliente. Esto es posible porque tres propiedades permanecen sin cambios en la sesión: ensamblado, methodInfo y type. Assembly almacena un enlace a la DLL cargada, la propiedad methodInfo contiene el método llamado desde la DLL y type describe el tipo de la DLL. El archivo install.zip es un paquete de instrucciones recibidas de un servidor que contiene archivos DLL, XML, imágenes, archivos de configuración, etc., y todo el código compilado que se ejecutará en un proceso futuro.

Este paso marca el comienzo de la comunicación entre el cliente y el servidor para realizar una tarea específica. Tan pronto como el cliente se inicialice con éxito para realizar una tarea específica, el servidor enviará solo el paquete de datos en forma cifrada, que debe procesarse, y también esperará una respuesta en forma cifrada.

Al ejecutar el código recibido del servidor, el sistema está "bloqueado", el cliente puede conectarse a las bases de datos, llamar a otras API, en particular, llamar a otros clientes que ejecutan las mismas o diferentes instrucciones. La conexión se realiza en el sistema de orquestación, donde el servidor busca el siguiente cliente disponible, solicita el resultado y el servidor redirige su respuesta al cliente. Esta orquestación de microservicios se llama "ExtendedService", y la única diferencia a nivel del cliente es que el cifrado está optimizado.

El problema técnico era reiniciar el cliente con otro paquete de instrucciones para ejecutar. Como la carga de memoria es estática en un contexto especial (servidor web), esto solo fue posible al reiniciar todo el proceso para procesar las DLL cargadas en la memoria. Para hacer esto, creamos eventos en Windows que ejecutamos desde una aplicación web que se ejecuta en una aplicación de escritorio. Esto es necesario porque estamos tratando con dos contextos diferentes en dos hilos de ejecución diferentes.

3.3.2. Servidor

El microservicio incorporado tiene una interfaz ILibraryMath, que proporciona el método SimpleMath, y la interfaz es implementada por la clase LibraryMath. La clase LibraryMath extiende la clase abstracta universal MicroCore, que tiene dos parámetros correspondientes para entrada y salida. Extendiendo esta clase abstracta, el método ProcessTask debe implementarse donde se escribe todo el código a ejecutar, y se llama a la función Ejecutar en la clase abstracta extendida para ejecutar este código en el método SimpleMath. Por lo tanto, es posible definir interfaces y métodos, no limitados a un nombre específico, sino que, pasando el código a través de una clase abstracta, obtendremos un control total sobre el código, que podemos distribuir entre diferentes clientes. Dentro de esta clase, fácilmente podemos tener más funciones y bibliotecas importadas,si están agrupados en un paquete

El siguiente paso es escribir esta interfaz en SimpleInjector, una biblioteca que facilita el despliegue de un patrón de inyección de dependencia con componentes acoplados libremente. Además de grabar clases intercaladas en el contenedor Simple Injector, para romper la dependencia entre los niveles de la aplicación (introduciendo dependencias de plantilla), necesitamos registrar la clase en el contenedor de almacenamiento de microservicios, que será escalado por la aplicación. Después de este paso, podremos utilizar la función proporcionada por la interfaz para el propósito creado.

Service1 implementa IService1 y extiende la clase abstracta MicroCore, y luego se registra con MicroContainer.RegisterMicro en este contenedor. Vale la pena mencionar la existencia de API disponibles en localohst / DynamicMicros / {Service} a través de las cuales los clientes se comunican con el servidor. Acciones importantes disponibles a través de estas API: el cliente se conecta, el cliente notifica al servidor de su actividad, los microservicios se expanden, etc. A continuación, presentamos las clases MicroCore y MicroContainer, que juntas forman la base de nuestra aplicación.

La clase MicroCore es una clase abstracta y universal y es responsable de llamar al código del método virtual ProcessTask. Esto se hace llamando al método Run, que a su vez llama al método público TaskManager. Tenga en cuenta que el microservicio, a su vez, también llamará a este método. Cuando se envía un paquete ZIP al cliente para cargarlo en la memoria y la ejecución, se envía con todas sus dependencias, incluida esta clase, que se utiliza para administrar el microservicio del cliente. El control de ejecución incluye deserializar / serializar el paquete de datos para enviar, llamar al código en sí, llamar a otras API, etc.

Volver al lado del servidor, controlar la ejecución del código consta de los siguientes pasos:

  1. Si se trata de una llamada de ExtendedService, se llamará al servidor para responder.
  2. Si un cliente está disponible para la solicitud, se le enviará para procesar el resultado; en el caso negativo, el servidor mismo procesará los datos.
  3. Solicitamos un cliente para el procesamiento de datos.
  4. Si el cliente tiene problemas, nuevamente solicitamos confirmación de disponibilidad, pero enviamos una respuesta del servidor (para evitar tiempos de inactividad y largos tiempos de espera).
  5. Registramos la actividad actual.

La clase MicroContainer es el espacio de administración para todo el microsistema incorporado. Aquí, los clientes que conectan la aplicación (servidor) se conectan, y hay llamadas de función que extienden la clase abstracta MicroCore para "servicios avanzados". Esta es una clase estática en la que la lista de tareas realizadas en microservicios, la lista de clientes conectados y la lista de tareas de clientes que realizan estas tareas se almacenan en el diccionario.

Cuando se inicie, la clase se registrará para su integración en el microservicio utilizando RegisterMicro. Esto sucederá solo una vez durante la inicialización. El método AddNewClient nos proporciona el registro de un nuevo cliente, el intercambio de claves, el registro de la dirección IP del servidor y el puerto en el que funcionará. El token recibido por el nuevo cliente se verificará antes de insertarse en la lista de clientes para confirmar su singularidad. Una vez que se establece la conexión con el cliente, el servidor llamará al método InstallService, que empaqueta los datos, los envía y, después de que el cliente responde, se agregará al diccionario para esta tarea. El tiempo de servicio que se asignará a cada cliente depende de la estrategia utilizada. Cuando inicia el microservicio abstracto MicroCore, llamado tanto en el servidor como en el cliente (con ExtendedService),Se realiza una solicitud de clientes disponibles para la tarea solicitada utilizando la función GetNextClient. Esta operación se realizará con mucha frecuencia y su complejidad afectará directamente el tiempo de respuesta de la aplicación. Es por eso que nuestro enfoque fue seleccionar aleatoriamente un cliente. Esto se hace rápidamente y de nuestros experimentos asegura una distribución uniforme de las llamadas.

Otra opción era implementar una lista round-robin, una solución que tiene el inconveniente de que, en el caso de un flujo de E / S de cliente grande, la actualización de la lista round-robin requerirá más tiempo y complejidad, lo que intentamos evitar. Se llama al método RecordClientError cuando el cliente no responde a la solicitud recibida. Después de responder a esta pregunta, se toma la decisión de guardar o eliminar este cliente.Los clientes se identifican de forma única por el código de token enviado por el cliente durante la inicialización, y cada microservicio se identifica por un espacio de nombres y un nombre de clase. Todos los recursos (clientes, código) se gestionan a través de esta unidad unitaria, que proporciona soporte para las operaciones necesarias.

Con respecto a la seguridad del sistema, se han tomado medidas para prevenir ataques, intercepciones y protección de datos. Todos los mensajes enviados entre el servidor y los clientes se cifran utilizando el algoritmo de clave DES simétrica y el intercambio de claves Diffie-Hellman entre el cliente y el servidor, que ocurre durante la inicialización del cliente. Los clientes disponibles y los programas en ejecución se almacenan en la memoria del servidor. Elegimos esta solución porque, en nuestra opinión, era la mejor opción, ya que proporciona acceso de alta velocidad a los datos, la información puede cambiar muy a menudo y el área de memoria es muy difícil de atacar.

3.4. Comportamiento dinámico de un sistema de microservicio.

En primer lugar, todas las computadoras en las que trabajarán los clientes pueden estar en la misma o en diferentes redes. Dos elementos tienen prioridad: (a) el tiempo dedicado a la transferencia de datos; y (b) la sobrecarga agregada por el sistema para la gestión de datos (por ejemplo, búsqueda de clientes, cifrado, descifrado, manejo de errores, etc.). Estábamos principalmente interesados ​​en el comportamiento de nuestro sistema en redes locales (LAN) y globales (WAN) (Fig. 4).


Higo. 4. Registro del sistema trabajando en una red de área local (la primera columna de registros) y global (la segunda columna de registros).

La columna Nombre de tarea contiene todos los registros realizados por la llamada del cliente para cada tarea, y las columnas Registros son las horas y la duración en ms para el procesamiento de cada tarea (a la izquierda en la red local y a la derecha en la red global). Tenga en cuenta que las tareas tienen el mayor tiempo de respuesta a la primera llamada, después de lo cual disminuye. Naturalmente, porque todas las descargas de memoria, guardar direcciones, etc., generalmente se realizan en la primera llamada. Las primeras tres tareas son operaciones matemáticas simples que generalmente se realizan en milisegundos, el tiempo que también se requiere para nuestro sistema.

Para una red local, tenemos un promedio de 20-30 milisegundos por tarea, que proviene del cifrado, el registro y la transmisión a través de la red (incluso si es local). Este modelo de comunicación LAN también se usa en la nube, donde las computadoras están ubicadas en el mismo lugar (centro de datos), y la comunicación entre ellas es a través de fibra óptica, el retraso de la red es mínimo. Los resultados se muestran en la fig. 4 en la columna izquierda de registros.

Para probar nuestra aplicación WAN, configuramos el enrutador para enrutar una llamada desde el puerto 80 a:http://192.168.1.160/(dirección de red) e IIS (Internet Information Services) lanzaron la aplicación, y fue accesible desde cualquier lugar fuera de la red local. Para ejecutar la aplicación a nivel de cliente, se requería el derecho a usar los puertos 8000: 9000 (puertos arbitrarios). Los clientes están dispuestos en puntos arbitrarios, la conexión a la IP pública sido comprobada a través de la API: https://api.ipify.org/. Los resultados se muestran en la fig. 4 en la columna de registro a la derecha.

En los resultados presentados en la fig. 4, los valores en la columna derecha de la revista en comparación con los valores en la columna izquierda de la revista son 16-17% más altos para las primeras tres tareas (sin comunicación con otros microservicios) y ± 10% para microservicios que descargaron documentos de Internet o interactuaron con la base de datos en servidor específico

4. Evaluación


En este estudio, monitoreamos el comportamiento del sistema tanto en la red local (conectando 5 computadoras a través de una red inalámbrica) como en la red global (usando el espacio de nombres mihaidm.ddns.net ), comparando nuestro sistema con un sistema monolítico, estas operaciones se realizan en el mismo computadora (ver tabla 1).

Tabla 1. Clasificación del sistema para redes.
cálculo (ms)escribir en la base de datos (ms)generación de pdf (ms)
localhost14.45815,449
lan254.40816,415
pálido544.82629.309


Las pruebas se llevaron a cabo secuencialmente en un dispositivo con 5 clientes conectados para pruebas de red. Cada tarea se completó 100 veces, evaluando el número total de milisegundos en todas las llamadas.

Fue un producto de dos números como un cálculo numérico. Un microservicio no interactúa con otros microservicios, la cantidad de información transmitida a través de la red es pequeña y la complejidad se minimiza para estudiar estrictamente el tiempo dedicado a las tareas de administración de servidores, clientes y redes. Si el servidor realiza el cálculo (localhost), primero se verifica si hay un cliente disponible y, dado que el cliente no está conectado, el servidor procesa el resultado. En el siguiente caso, la presencia de clientes en la red local muestra la finalización de la tarea en condiciones de operación de red muy rápida y, desde el lado del procesamiento, encriptación / desencriptación, encontrando la respuesta del cliente. Para 100 ejecuciones, el tiempo promedio requerido para completar la operación fue de 25 ms, que es un valor prometedor teniendo en cuenta la relación flexibilidad / velocidad. En caso de WAN, el tiempo es el dobleque en la red local (54 ms), esto se debe al proceso de cifrado, los costos de transporte, pero para la ejecución real se requiere medio milisegundo.

Otra tarea que investigamos es escribir en la base de datos. En particular, la palabra que se escribirá en la base de datos se toma como un parámetro. Estamos interesados ​​en la rapidez con que el cliente se pondrá en contacto con una base de datos ubicada fuera del área local (para este estudio, la base de datos se encuentra en www.my.gearhost.com ). Tenga en cuenta que los valores de tiempo de ejecución en LAN y localhost están cerca. En la red global, la diferencia es notable, porque el procesamiento, la administración de datos y los clientes no requieren tanto tiempo como el rango de clientes que se conecta a la base de datos para insertar el valor.

La última tarea realizada en este estudio fue la creación de un archivo PDF, nuestro enfoque fue estimar el tiempo de transmisión de los datos en el sistema. Para hacer esto, descargamos el archivo PDF de www.pdf-archive.com/2018/05/14/diploma/diploma.pdf , que se carga en la memoria. El sistema escribirá el nombre en una posición específica y devolverá el resultado (en forma de vectores de bytes) al servidor. Para un host local y una red local, una diferencia de aproximadamente 1000 ms representa el tiempo requerido para cifrar y transferir archivos PDF localmente. Para la WAN, el valor resultante es mayor porque el costo de transmisión del vector byte es muy alto.

5. Conclusiones y trabajos futuros.


La naturaleza general y abstracta de la arquitectura del sistema, presentada en este trabajo en el lado del servidor, dificultó el diseño, ya que tanto el servidor como el cliente ejecutan el mismo código. Podemos argumentar que la arquitectura actual es compacta, simple, fácil de entender y expandir; el cliente puede realizar las tareas asignadas por el servidor, el servidor es un monolito y la interfaz del cliente.

La arquitectura propuesta hace que sea muy fácil crear nuevos microservicios, que luego se integran automáticamente en el sistema embebido. Elementos innovadores de esta arquitectura: puede escalar muy fácilmente, cada nuevo cliente recibe una tarea del servidor de acuerdo con la estrategia seguida (las tareas más caras, las más comunes, una combinación de las dos listadas anteriormente o simplemente una estrategia arbitraria). De hecho, tenemos un monolito con la flexibilidad de un sistema de microservicio. El servidor procesa la distribución dinámica de tareas entre clientes, proporcionando una escala dinámica basada en una serie de parámetros (el número de llamadas a la tarea, su tiempo de ejecución o una combinación de los mismos).

Una de las direcciones futuras tiene en cuenta que este sistema puede integrarse con éxito en un sitio web o sistema API con un marcado carácter aplicativo. La arquitectura propuesta se puede mejorar y ampliar en cualquier momento debido a la disponibilidad para varias plataformas (por ejemplo, para teléfonos móviles).

Otra dirección en el futuro que estamos considerando se considera extremadamente atractiva hoy en día: es que el usuario proporciona potencia informática a cambio de una tarifa (por ejemplo, el sistema BITCOIN), nuestra aplicación está desarrollada para ejecutar microservicios en ciertas computadoras.

Enlace fuente


Este estudio fue publicado con el apoyo del programa POC-A1-A1.2.3-G-2015, como parte del proyecto PrivateSky (P_40_371 / 13/01/01/2016) y el proyecto README "Aplicación interactiva e innovadora para evaluar la legibilidad de los textos en rumano y mejorar el usuario estilos de escritura ", contrato No. 114 / 09.15.2017, código MySMIS 2014 119286.

Referencias


[1] Dragoni, N., Giallorenzo, S., Lluch-Lafuente, AL, Mazzara, M., Montesi, F., Mustafin, R. (2017a) "Microservicios: ayer, hoy y mañana". Mazzara M., Meyer B. (eds.), Ingeniería de software actual y posterior. Saltador
[2] Mazzara, M., Khanda, K., Mustafin, R., Rivera, V., Safina, L. y Silitti, A. (2018) "Microservices Science and Engineering". En: P. Ciancarini, S. Litvinov, A. Messina, A., Sillitti, G. Succi (eds.) Actas de la 5ta Conferencia Internacional de Ingeniería de Software para Aplicaciones de Defensa, SEDA 2016, Springer, 10-20.
[3] Dragoni, N., Lanese, I., Larsen, ST, Mazzara, M., Mustafin, R. y Safina, L. (2017b) "Microservicios: Cómo hacer que su aplicación sea a escala". En: Petrenko A., Voronkov A. (eds.) Perspectivas de la informática del sistema. PSI 2017. Lecture Notes in Computer Science, 10742. Springer, Cham.
[4] Melis, A., Mirri, S., Prandi, C., Prandini, M., Salomoni, P. y Callegati, F. (2016) "Un caso de uso de arquitectura de microservicios para personas con discapacidad". En la 2da Conferencia Internacional EAI sobre Objetos inteligentes y tecnologías para el bien social, DOI: 10.1007 / 978-3-319-61949-1_5.
[5] Zimmermann, O. (2017) "Principios de microservicios: enfoque ágil para el desarrollo y despliegue de servicios, informática - investigación y desarrollo", 32 (3-4): 301-310.
[6] Xia, C., Zhang, Y., Wang, L, Coleman, S. y Liu, Y. (2018) "Sistema de robótica en la nube basado en microservicios para el espacio inteligente". En: Robotics and Autonomous Systems 110, DOI: 10.1016 / j.robot.2018.10.001.
[7] Bogner, J., Fritzsch, J., Wagner, S. y Zimmermann, A. (2019) "Microservicios en la industria: conocimientos sobre tecnologías, características y calidad de software". En la Conferencia Internacional IEEE 2019 sobre Talleres de Arquitectura de Software (ICSAW) en: Hamburgo, Alemania.
[8] Akentev, E., Tchitchigin, A., Safina, L. y Mzzara, M. (2017) "Verificador de tipo verificado para el lenguaje de programación Jolie", https: // arXiv.org/pdf/1703.05186.pdf.
[9] Černý, T., Donahoo, MJ y Trnka, M. (2018) "Comprensión contextual de la arquitectura de microservicios: direcciones actuales y futuras". ACM SIGAPP Applied Computing Review 17 (4): 29-45, DOI: 10.1145 / 3183628.3183631.
[10] Larucces, X., Santamaría, I., Colomo-Palacios, R. y Ebert, C. (2018) "Microservicios". En: Software IEEE, 35/3: 96-100.
[11] Kalske, M. (2017) "Transformando la arquitectura monolítica hacia la arquitectura de microservicios". M.Sc. Tesis, Univ. de helsinki.
[12] Lenarduzzi, V. y Taibi, D. (2016) "MVP explicado: un estudio de mapeo sistemático sobre las definiciones de producto mínimo viable". En la 42ª Conferencia Euromicro sobre Ingeniería de Software y Aplicaciones Avanzadas (SEAA), 112-119.
[13] Taibi, D., Lenarduzzi, V., Janes, A., Liukkunen, K. y Ahmad, MO (2017) "Comparación de los requisitos de descomposición dentro de los procesos de desarrollo Scrum, Scrum con Kanban, XP y Banana". En: Baumeister H., Lichter H., Riebisch M. (eds.) Procesos ágiles en ingeniería de software y programación extrema. Lecture Notes in Business Information Processing, 283. Springer, Cham.
[14] Gómez, A., Benelallam, A. y Tisi, M. (2015) "Modelo descentralizado de persistencia para la computación distribuida". En el 3er Taller BigMDE, L'Aquila, Italia.
[15] Kandave, KR (2018) "Computación de alto rendimiento en Azure". Nanette Ray (ed.), AzureCAT, Microsoft Corporation.
[16] Sreenivas, V., SriHarsha, S. y Narasimham, C. (2012) "Un modelo de nube para implementar SaaS". En: Advanced Materials Research 341-342, Trans Tech Publications, Suiza, 499-503.
[17] Badidi, E. (2013) "Un marco para la selección y provisión de software como servicio". En: International Journal of Computer Networks & Communications (IJCNC), 5 (3): 189-200.
[18] Lynn, T., Rosati, P., Lejeune, A. y Emeakaroha, V. (2017) "Una revisión preliminar de las plataformas empresariales de computación en la nube sin servidor (Functionas-a-Service)". En la IX Conferencia Internacional IEEE 2017 sobre Ciencia y Tecnología de Computación en la Nube, 162-169.
[19] Adzic, G. y Chatley, R. (2017) "Computación sin servidor: impacto económico y arquitectónico". En: ESEC / FSE'17, 4-8 de septiembre de 2017, Paderborn, Alemania, ACM.
[20] Diffie, W. y Hellman, M. (1976) "Nuevas direcciones en criptografía". En: IEEE Transactions on, Information Theory, 22 (6): 644–654.
[21] Kratzke, N. (2015) "Acerca de los microservicios, contenedores y su impacto subestimado en el rendimiento de la red". En la NUBE Comput. 2015, 180 arxiv.org/abs/1710.04049 .

Aprende más sobre el curso

All Articles