dmlls / jizt-tfg

Servicio de Resumen de Textos con AI en la Nube (versión TFG).
https://dmlls.github.io/jizt-tfg-website/
GNU General Public License v3.0
13 stars 3 forks source link

Diseño de la Arquitectura de JIZT #67

Closed dmlls closed 3 years ago

dmlls commented 3 years ago

JIZT empleará una arquitectura basada en microservicios (microservices architecture, en inglés). Este tipo de arquitectura se contrapone a las arquitecturas monolíticas, en las cuales los diferentes componentes están estrechamente interrelacionados.

En nuestro caso, requerimos de una arquitectura en la que las dependencias entre los diferentes componentes sean lo más flexibles posibles. Esto se debe a que existen numerosos modelos de generación de resúmenes, y queremos poder darle la opción al usuario de elegir qué modelo emplear.

Además, el campo del Procesamiento de Lenguaje Natural (NLP, por sus siglas en inglés) es un área bajo activo desarrollo, en el que aparecen modelos más y más potentes cada pocos meses. Por ello, nuestra arquitectura debe ser capaz de adaptarse a estos cambios de manera local, de forma que el reemplazo de un componente sea transparente al resto.

En un principio existirán los siguientes microservicios:

Los anteriores microservicios se ejecutarán dentro de contenedores Docker orquestrados mediante Kubernetes, de forma que el número de contenedores en ejecución se pueda escalar de manera automatizada para adaptarse a las demandas de los clientes.

Existen dos cuestiones fundamentales a abordar a la hora de emplear este tipo de arquitectura:

  1. La generación de resúmenes es una tarea que se puede dilatar varios segundos en el tiempo, dependiendo de factores como la longitud del texto o de los parámetros con los que se quiera generar el resumen. Por lo tanto, realizar peticiones HTTP síncronas queda descartado, puesto que estas no se pueden mantener activas durante periodos de tiempo tan prolongados. La pregunta es: ¿cómo se gestionará el asincronismo?

  2. El proceso de resumen de los textos es principalmente secuencial, de forma que las salidas de unos microservicios será las entradas de los siguientes. Por tanto, la siguiente pregunta es: ¿cómo se llevará a cabo la comunicación entre ellos? Y, ¿cómo sabrá un microservicio a que otro microservicio debe enviarle su output?

1. Asincronismo

La solución para evitar llevar a cabo peticiones HTTP demasiado largas es simplemente no tener que hacerlas. Nuestra API proporcionará un mecanismo para ello. Veamos como funciona.

1.1 Petición HTTP POST

El cliente comienza realizando una petición POST incluyendo en el cuerpo de la petición el texto que quiere resumir. La API le responde con un identificador único del resumen, el summary_id:

0 0 6_logic_1

1.2 Peticiones HTTP GET sucesivas

En ese momento, el cliente puede llevar a cabo peticiones HTTP GET con el iddel resumen de manera periódica a fin de consultar el estado del mismo. Los diferentes estados en los que un resumen puede estar son:

0 0 6_logic_2

Una de las principales ventajas de poder consultar el estado del resumen es poder ofrecerle al usuario retroalimentación acerca del proceso de resumen, ya que de lo contrario no podría saber si el sistema se ha quedado "colgado" o sigue trabajando.

1.3 Petición HTTP GET final

En algún momento, el estado del resumen pasará a ser completed y la respuesta contendrá el resumen generado:

0 0 6_logic_3

Los diferentes resúmenes se almacenarán en una base de datos gestionada por el Dispatcher, de manera que:

  1. Cuando el Dispatcher recibe una petición POST, lo primero que hace es calcular un summary_id y ver si este ya existe en la base de datos. El summary_id se genera de tal forma que dos textos idénticos tendrán el mismo summary_id. Por tanto, si un texto ya hubiera sido resumido anteriormente, no se volvería a generar su resumen, si no que se recuperaría de la base de datos.
  2. Si el texto no hubiera sido resumido previamente, el Dispatcher pasaría el texto a resumir al Pre-procesador de textos. Además, almacenaría el resumen en la base de datos. El estado de dicho resumen sería preprocessing, y su output (es decir, el resumen) null.
  3. El Dispatcher iría actualizando el estado del resumen a medida que va pasando por las diferentes etapas (codificación, resumen, etc.).
  4. Cada vez el cliente realizara una petición GET con el id del resumen, consultaría su estado en la base de datos, y respondería en consecuencia.

2. Arquitectura dirigida por eventos: Apache Kafka

Para resolver el segundo punto, es decir, cómo implementar la comunicación entre microservicios, emplearemos una Arquitectura dirigida por eventos (o Event-driven architecture, EDA, en inglés). En nuestro caso se considerará como un evento cada vez que un microservicio acabe su trabajo,

Para implementar este paradigma arquitectónico, haremos uso de Apache Kafka, una solución software que, si bien requiere cierta labor de configuración, facilita enormemente el despliegue y escalado de este tipo de arquitectura.

Kafka introduce el concepto de topic, que vendría a ser el lugar en el que se recogen los diferentes eventos. Existirán una serie de productores y de consumidores. Los productores se encargarán de publicar mensajes en los topics apropiados, y los consumidores de recoger dichos mensajes.

La figura incluida a continuación puede ayudar a comprender mejor estos conceptos:

0 0 5_jizt_architecture

En el anterior diagrama, los topics serían aquellos que aparecen incluidos dentro del Kafka Broker (que es el componente encargado de gestionarlos):

El Dispatcher, por su parte, consume de todos los anteriores topics a fin de actualizar el estado del resumen en cuestión.

clopezno commented 3 years ago

Una descripción muy precisa, muy bien explicada , presentada y justificada. La implementación de la computación dirigida por eventos con kafka es muy innovadora. Me parece un diseño arquitectónico perfecto.