Este es el segundo tutorial de un recorrido de aprendizaje que te enseña a modularizar y contenerizar una aplicación monolítica.
El recorrido de aprendizaje consta de los siguientes tutoriales:
- Descripción general
- Información sobre el monolito
- Modularizar el monolito (este tutorial)
- Preparar la aplicación modular para la contenerización
- Contenerizar la aplicación modular
- Desplegar la aplicación en un clúster de GKE
En el tutorial anterior, Entender el monolito, has aprendido sobre una aplicación monolítica llamada Cymbal Books. Has ejecutado el monolito en tu máquina local y has descubierto que las diferentes partes del monolito se comunican entre sí a través de sus endpoints.
En este tutorial, verás cómo dividir el monolito en módulos para prepararlo para la contenerización. No es necesario que realices los pasos de modularización, ya que el código ya se ha actualizado. Tu tarea consiste en seguir el tutorial y explorar la versión modular de la aplicación en el repositorio para ver en qué se diferencia del monolito original.
Costes
Puedes completar este tutorial sin incurrir en ningún cargo. Sin embargo, si sigues los pasos del último tutorial de esta serie, se aplicarán cargos a tu cuenta deGoogle Cloud . Los costes empiezan cuando habilitas GKE y despliegas la aplicación Cymbal Books en un clúster de GKE. Estos costes incluyen los cargos por clúster de GKE, tal como se indica en la página de precios, y los cargos por ejecutar máquinas virtuales de Compute Engine.
Para evitar cargos innecesarios, inhabilita GKE o elimina el proyecto una vez que hayas completado este tutorial.
Antes de empezar
Antes de empezar este tutorial, asegúrate de haber completado el primero, Entender el monolito. En este tutorial, ejecutarás la versión modular de Cymbal Books en tu máquina local. Para ello, debes configurar tu entorno. Si ya has completado el primer tutorial, habrás clonado un repositorio de GitHub. Las tres versiones de la aplicación Cymbal Books se encuentran en ese repositorio, dentro de las siguientes carpetas:
monolith/
modular/
containerized/
Comprueba que estas carpetas estén en tu máquina antes de continuar. Además, asegúrate de que el entorno virtual book-review-env
esté activo. Si necesitas recordar cómo activarlo, consulta el artículo Crear y activar un entorno virtual del primer tutorial. Al activar el entorno, te aseguras de que la versión modular de la aplicación tenga todo lo que necesita para ejecutarse.
¿Qué es la modularización?
En este tutorial, aprenderás a modularizar la aplicación monolítica para prepararla para la contenerización. La modularización es el proceso de convertir un monolito en una aplicación modular. Como has visto en el tutorial anterior, la característica distintiva de un monolito es que sus componentes no se pueden ejecutar ni escalar de forma independiente. Una aplicación modular es diferente: su funcionalidad se divide en módulos que pueden ejecutarse y escalarse de forma independiente.
Aunque la modularización y la contenerización suelen hacerse juntas, en esta serie de tutoriales se tratan como pasos independientes para ayudarte a entender cada concepto con claridad. En este tutorial se explica cómo modularizar un monolito y, en un tutorial posterior, cómo contenedorizar la aplicación modular.
Modularización incremental
En los entornos de producción, normalmente se modulariza un componente cada vez. Modulariza el componente, integra el módulo con el monolito y asegúrate de que todo funcione antes de trabajar en el siguiente componente. Este estado híbrido, en el que algunos componentes se modularizan mientras que otros siguen formando parte del monolito, se denomina microlito. Sin embargo, en este tutorial, todos los componentes de la aplicación se modularizan al mismo tiempo para ofrecer un ejemplo completo de cómo modularizar una aplicación.
Cómo modularizar el monolito
En esta sección, aprenderás cómo se dividió el monolito de Cymbal Books en módulos independientes. Se proporcionan pasos para ayudarte a entender el proceso de modularización y que puedas aplicarlo a tus propias aplicaciones. Sin embargo, no es necesario que sigas estos pasos en este tutorial, ya que el repositorio clonado ya incluye la versión modular de la aplicación:
- Identificar las funciones distintas de la aplicación
- Crea los módulos
- Habilitar la comunicación entre los módulos
- Dar a cada módulo acceso solo a los datos que necesita
Identificar las funciones distintas de la aplicación
El primer paso para modularizar el monolito de Cymbal Books es identificar sus funciones principales. En la aplicación de ejemplo Cymbal Books, el monolito tiene las cuatro funciones distintas siguientes:
- Servir la página principal
- Servir detalles de libros
- Publicar reseñas de libros
- Servir imágenes de portada de libros
Crear los módulos
Como has visto en el tutorial anterior, el monolito es una sola aplicación Flask que implementa las cuatro funciones, que se identificaron en la sección anterior, como controladores de rutas. Para modularizar la aplicación, se toma cada controlador de ruta y se coloca en su propia aplicación Flask. En lugar de tener una aplicación Flask con cuatro controladores de ruta, se tienen cuatro aplicaciones Flask, cada una con un solo controlador de ruta.
En el siguiente diagrama se ilustra esta transformación de una sola aplicación Flask en cuatro aplicaciones Flask independientes:
En la aplicación modular, cada aplicación Flask se ejecuta de forma independiente y escucha en un puerto diferente (8080, 8081, 8082 y 8083), tal como se muestra en el diagrama. Esta configuración es necesaria porque, cuando pruebes la aplicación modular más adelante en este tutorial, ejecutarás todos los módulos en la misma máquina. Cada aplicación necesita un número de puerto diferente para evitar conflictos.
El módulo de la página principal tiene dos responsabilidades: sirve la página principal y se comunica con los demás módulos para recoger los datos que se deben mostrar en una página web. Cada uno de los demás módulos se centra en una sola función: servir reseñas, detalles o imágenes. Estos módulos no se comunican entre sí, sino que solo responden a las solicitudes del módulo de la página principal.
Aunque el módulo de la página principal tiene un papel de coordinación adicional, la aplicación sigue siendo modular, ya que puedes actualizar cualquier módulo sin que afecte a los demás. La aplicación Flask grande se ha dividido en cuatro partes, cada una de las cuales gestiona una parte específica de la funcionalidad de la aplicación.
Habilitar la comunicación entre los módulos
Después de crear los módulos, el siguiente paso es asegurarse de que puedan comunicarse entre sí. En la aplicación Cymbal Books, esta lógica de comunicación ya se ha implementado. En la carpeta modular/
del código que has descargado, puedes ver que cada una de las funciones principales de la aplicación (servir la página principal, los detalles de los libros, las reseñas y las imágenes) se implementa como una aplicación Flask independiente. Cada una de estas aplicaciones define su propio endpoint HTTP y los módulos se comunican enviando solicitudes HTTP a esos endpoints.
Modularizar el monolito de Cymbal Books fue sencillo. El monolito tiene componentes bien definidos que se implementan como controladores de rutas, y cada controlador de rutas tiene un endpoint bien definido. Cuando estos controladores de ruta se colocan en aplicaciones Flask independientes, conservan su capacidad de comunicarse a través de sus endpoints. El sencillo acto de colocar los controladores de ruta en aplicaciones Flask independientes crea los módulos y permite que los módulos se comuniquen entre sí.
Una estrategia habitual para la comunicación entre módulos es implementar APIs REST, que permiten que los módulos se envíen solicitudes HTTP entre sí. Así es como funciona en Cymbal Books: cada módulo define endpoints REST mediante las herramientas integradas de Flask. Otro enfoque popular es gRPC, que permite que los módulos llamen directamente a las funciones de los demás.
Por qué la comunicación es sencilla en Cymbal Books
Cada módulo de la aplicación modular es una aplicación Flask independiente que se ejecuta en un servidor web. Por ejemplo, el módulo de la página principal sirve la página principal, mientras que el módulo de detalles del libro sirve los detalles del libro. La comunicación entre los módulos es sencilla, ya que los servidores web están diseñados para gestionar solicitudes y respuestas HTTP. Cada módulo expone endpoints que otros módulos pueden usar para solicitar datos.
Dar a cada módulo acceso solo a los datos que necesita
Para modularizar correctamente el monolito, debes asegurarte de que cada módulo solo tenga acceso a los datos que necesita. Este principio, conocido como aislamiento de datos, es un elemento fundamental para crear una arquitectura verdaderamente modular.
Un error frecuente que cometen los usuarios durante la modularización es permitir que varios módulos accedan a los mismos datos, como una sola base de datos. Este tipo de implementación genera problemas como los siguientes:
- Acoplamiento estrecho: si cambia la estructura de los datos compartidos (por ejemplo, si se cambia el nombre de una tabla de la base de datos o se añade una columna), se debe actualizar cada módulo que dependa de esos datos. Una modularización adecuada evita este problema.
- Problemas de tolerancia a fallos: cuando varios módulos usan la misma fuente de datos, los fallos en el tiempo de ejecución de un módulo (por ejemplo, consultas no válidas o un tráfico excesivo) pueden interrumpir otros módulos. Si falla una parte del sistema, puede provocar fallos en otras partes del sistema.
- Cuellos de botella en el rendimiento: una única fuente de datos compartida puede convertirse en un cuello de botella, lo que significa que puede ralentizar toda la aplicación cuando varios módulos intentan interactuar con ella.
Para evitar estos problemas, cada módulo debe tener su propia fuente de datos.
Si Cymbal Books hubiera usado una base de datos para almacenar sus datos, tendrías que replicar o particionar la base de datos para aplicar el aislamiento de datos y asegurarte de que cada módulo solo acceda a los datos que necesita. La replicación implica mantener copias independientes de la base de datos para cada módulo, mientras que la partición restringe el acceso a tablas o filas específicas. Ambos enfoques evitan que los módulos interfieran con los datos de los demás.
En el siguiente diagrama se compara la arquitectura de la aplicación de libros monolítica con la arquitectura modular de la aplicación de libros:
La implementación del monolito no sigue el principio de aislamiento de datos, ya que las funciones del monolito acceden a un solo directorio data/
.
Por el contrario, la aplicación modular consigue cierto grado de aislamiento de datos dividiendo los datos en directorios independientes y asegurándose de que cada módulo interactúe solo con los datos que le corresponden:
- El módulo de detalles del libro solo obtiene datos del directorio
details_data/
. - El módulo de reseñas de libros solo obtiene datos del directorio
reviews_data/
. - El módulo Imágenes solo obtiene datos del directorio
images/
.
En otro tutorial, se muestra cómo el uso de contenedores en la aplicación puede mejorar aún más el aislamiento de los datos.
Lo que acabas de ver
En el sector del desarrollo de software, a menudo se utilizan los términos microservicios y sistemas distribuidos. En esta sección se explica cómo se relacionan estos términos con la implementación modular de Cymbal Books.
Microservicios
Los microservicios son módulos autónomos que realizan tareas específicas. Estos módulos se comunican con otros módulos a través de interfaces, como los endpoints.
Cada módulo de la versión modular de Cymbal Books se ajusta a esta definición y, por lo tanto, se puede denominar microservicio. Cuando la aplicación modular se contenga en un tutorial posterior, el código que se ejecute dentro de un contenedor también se podrá denominar microservicio, ya que es el mismo código que se ejecuta dentro de un módulo.
Sistemas distribuidos
Un sistema distribuido consta de módulos independientes que se comunican a través de una red para alcanzar un objetivo común. Estos módulos pueden ejecutarse en diferentes máquinas, pero funcionan juntos como un único sistema.
La aplicación modular Cymbal Books también se ajusta a esta definición: sus módulos se ejecutan de forma independiente e intercambian datos a través de HTTP, pero juntos funcionan como un único sistema. En la siguiente sección, ejecutarás todos los módulos en una sola máquina para simplificar el proceso, pero no es obligatorio. Cada módulo podría ejecutarse fácilmente en un servidor diferente, por lo que la versión modular de la aplicación Cymbal Books se puede clasificar como un sistema distribuido.
Probar la implementación modular
Ahora que has visto cómo se transforma el monolito de Cymbal Books en una aplicación modular cuyos módulos son aplicaciones Flask, puedes probar la aplicación y ver que cada módulo se ejecuta de forma independiente.
En este tutorial, ejecutarás los módulos en la misma máquina. Sin embargo, también puedes ejecutar cada módulo en un servidor independiente, ya que cada módulo es autónomo y puede comunicarse con los demás módulos a través de sus endpoints.
Configurar un entorno
Sigue estos pasos para prepararte para las pruebas:
En tu terminal, ve al directorio
modular
del repositorio clonado:cd modular
Asegúrate de que el entorno virtual
book-review-env
esté activo. Si necesitas recordar los pasos de activación, consulta el artículo Crear y activar un entorno virtual.
Iniciar la aplicación Flask
La carpeta /modular
contiene una secuencia de comandos bash que inicia todas las aplicaciones Flask simultáneamente. Cada módulo de la aplicación escucha en un puerto único, como 8080 u 8081:
- Aplicación Flask de la página principal (home.py): puerto 8080
- Aplicación Flask de detalles de libros (book_details.py): puerto 8081
- Aplicación Flask de reseñas de libros (book_reviews.py): puerto 8082
- Aplicación Flask de imágenes (images.py): puerto 8083
Cada módulo debe escuchar en un número de puerto único, ya que todos los módulos se ejecutan en la misma máquina. Si cada módulo estuviera en un servidor diferente, cada uno podría escuchar en el mismo número de puerto sin crear conflictos de puertos.
Ejecuta la secuencia de comandos bash con este comando:
bash ./start_services.sh
La secuencia de comandos crea un archivo de registro independiente para cada aplicación Flask (por ejemplo, home.py.log
y book_details.py.log
) para ayudarte a identificar cualquier problema de inicio.
Cuando la secuencia de comandos se completa correctamente, aparece este mensaje:
All services have been started. Access the app at http://localhost:8080/
Probar cada aplicación Flask
Prueba los módulos visitando las siguientes URLs en tu navegador:
- Página principal:
http://localhost:8080/
muestra la página principal de la aplicación modularizada Cymbal Books. Esta página obtiene los detalles, las reseñas y las imágenes de los libros haciendo solicitudes a los demás módulos. - Detalles del libro:
http://localhost:8081/book/1
devuelve los detalles del libro con el ID 1. Esta respuesta son datos JSON que la aplicación formatea y muestra de una forma más legible. - Reseñas de libros:
http://localhost:8082/book/1/reviews
obtiene y devuelve las reseñas del libro con el ID 1. Las reseñas están en formato JSON. El módulo de la página principal solicita estos datos y los integra en la página de detalles del libro. - Imágenes:
http://localhost:8083/images/fungi_frontier.jpg
sirve la imagen de la portada del libro Fungi Frontier. Si la URL es correcta, la imagen debería cargarse directamente en el navegador.
Detener las aplicaciones Flask
Cuando termines las pruebas, detén todas las aplicaciones Flask con este comando:
kill $(cat home.py.pid book_details.py.pid book_reviews.py.pid images.py.pid)
Resumen
En este tutorial se ha explicado cómo modularizar el monolito de Cymbal Books. El proceso consta de los siguientes pasos:
- Identificar los componentes distintos de la aplicación
- Crear los módulos
- Asegurarse de que cada módulo solo tenga acceso a los datos que necesita
Después, has probado la implementación modular en tu máquina local.
Siguientes pasos
En el siguiente tutorial, Prepara la aplicación modular para la contenedorización, aprenderás a preparar la aplicación modular para la contenedorización actualizando los endpoints para usar nombres de servicio de Kubernetes en lugar de localhost
.