El tema de la arquitectura de microservicios se ha hecho cada vez más popular en los últimos años. El motivo estriba en las numerosas ventajas que aporta este estilo arquitectónico modular, especialmente cuando se trata de diseñar aplicaciones complejas.

Ya hemos cubierto los pros y los contras de la implementación de la arquitectura de microservicios y hemos comparado los microservicios con la arquitectura monolítica aquí. En este artículo, compartiremos soluciones a problemas comunes que pueden surgir en el camino de la construcción de la arquitectura de microservicios para su aplicación. Para ser más precisos, describiremos enfoques para implementar la comunicación interservicios en aplicaciones basadas en microservicios con la ayuda del broker de mensajes Azure Service Bus. Aprenderá algunos aspectos básicos sobre los corredores de mensajes y cómo configurarlos y empezar a utilizarlos en sus aplicaciones.

Este artículo ha sido escrito para desarrolladores .NET y arquitectos de soluciones que quieran mejorar su aplicación basada en microservicios y encontrar el enfoque adecuado para implementar la comunicación entre microservicios. Los ejemplos de este artículo se han escrito utilizando el marco .NET Core.

¿Pueden los microservicios ser totalmente independientes?

La arquitectura de aplicaciones basada en microservicios está diseñada para permitir el funcionamiento independiente de pequeñas partes de un gran sistema. Cada microservicio es responsable de una función específica del sistema, y cada servicio puede estar relacionado con un almacenamiento de datos diferente. Por ejemplo, un servicio puede almacenar los datos en una base de datos Microsoft SQL, y otro puede utilizar un almacenamiento NoSQL, como MongoDB, etc.

Por otro lado, hay muchos casos en los que no podemos crear partes totalmente independientes. Por ejemplo, creamos el microservicio de Seguridad, responsable de la seguridad y la autorización de los usuarios. También necesitamos el microservicio de Comunicación para hacer un seguimiento de los mensajes, las notificaciones y otras instancias de interacción con el usuario. Ambos microservicios dependen de la misma base de usuarios, pero son independientes en cuanto al tipo de información del usuario que almacenan, conservando sólo los datos esenciales para su funcionamiento. En este escenario, la idea principal es minimizar la dependencia de cada servicio con respecto a otro. A veces necesitamos realizar algunas consultas entre servicios o incluso almacenar algunos datos similares en diferentes lugares. En este punto, debemos proporcionar una capacidad para que los microservicios se comuniquen entre sí.

¿Por qué necesitamos construir la comunicación entre los servicios?

Como hemos mencionado anteriormente, puede ser realmente difícil crear una arquitectura totalmente independiente porque en algunos casos, sus microservicios necesitan comunicarse entre sí. Por cierto, puede necesitar la comunicación incluso en el caso de que almacene datos similares en diferentes almacenamientos. Para dar ejemplos, tomaremos uno de nuestros proyectos existentes, en el que tuvimos que implementar la comunicación interservicios.

Tenemos una aplicación que consiste en una lista de microservicios. Para nuestro ejemplo, echaremos un vistazo sólo a algunos de ellos: autorización, análisis, pedidos, pasarela y servicio de correo electrónico. Cada servicio tiene su propia base de datos para almacenar los datos de forma independiente.

Examinemos brevemente el propósito de cada microservicio:

  • Pasarela. Distribuye las solicitudes a otros microservicios en función de su destino. Los demás microservicios sólo aceptan peticiones del microservicio de la pasarela. La puerta de enlace es el único microservicio abierto a las solicitudes externas.
  • Autorización. Proporciona las principales funciones de seguridad para toda la aplicación: inicio de sesión del usuario, cierre de sesión, registro, recuperación de la contraseña, etc.
  • Correo electrónico. Proporciona la capacidad de enviar varios mensajes de correo electrónico a los usuarios, como recordatorios, boletines, correos de recuperación de contraseñas, etc.
  • Pedidos. Es el microservicio responsable de la ejecución de todas las operaciones principales de los pedidos, como la creación, la actualización, la eliminación, la visualización, el cálculo, la fijación de precios, el seguimiento de los pedidos, y muchas más. Este servicio contiene toda la información sobre los pedidos en el sistema, y es el principal almacén de datos de la aplicación
  • Análisis. Proporciona algunas funciones para ver las estadísticas y los análisis, como el número de pedidos abiertos en el sistema, el tiempo que llevan abiertos y otros datos necesarios para una toma de decisiones eficaz. Puede que este servicio no almacene todos los detalles del pedido, pero permite acceder rápida y cómodamente a datos cruciales presentados en un formato visualmente atractivo.

Como puede ver, cada microservicio es responsable de diferentes operaciones y, en su mayoría, no requiere el mismo almacenamiento de datos, porque los datos de cada microservicio son bastante diferentes. La excepción es el microservicio de análisis. Este debe tener la misma información sobre los pedidos en el sistema. Sin embargo, ¿debemos utilizar el mismo almacenamiento de datos?

¿Por qué es mejor tener un almacenamiento de datos diferente para cada microservicio?

Si construye una arquitectura basada en microservicios para su aplicación, debe cuidar la escalabilidad de la misma. En el caso de utilizar el mismo almacenamiento de datos para diferentes microservicios, tendrá problemas de escalabilidad. Si uno de sus servicios se sobrecarga, puede afectar también al almacenamiento de datos. Así que deberá escalar más elementos para mejorar el rendimiento de uno de sus servicios. En este caso, las instancias de la aplicación son mucho más grandes. Tenga en cuenta que los datos colocados en un almacenamiento pueden afectar al rendimiento. Además, puede provocar una carga pesada.

Para evitar estos problemas, puede utilizar un almacenamiento de datos diferente para cada microservicio. Diseñar el almacenamiento para que se adapte a las necesidades de un servicio concreto puede mejorar el rendimiento de las operaciones con procesamiento de datos. Además, puede simplificar el desarrollo y el trabajo con los datos, ya que se almacenan en un formato cómodo y listo para usar y se evita la conversión de datos.

Cualquier cambio en su microservicio no creará errores ocultos en otros microservicios, porque son independientes. Si utiliza el mismo almacenamiento y toma la decisión de cambiar algún modelo de entidad, no tendrá que repetir estos cambios en todos los demás servicios que utilicen el mismo almacenamiento de datos.

Para nuestro caso con los microservicios de análisis y pedidos, tenemos algunos detalles adicionales. El servicio de Pedidos puede cambiar los pedidos en cualquier momento y tiene una gran carga. El servicio de Análisis sólo debe calcular algunos datos para los gráficos y los cuadros de mando. No es necesario obtener todos los cambios de forma inmediata, por lo que podemos realizar estas operaciones por horario (cada hora, diariamente, etc.).

En resumen, tenemos que sincronizar nuestros datos en estos dos servicios y recalcularlos cuando las entidades de datos se modifican. Esto se puede resolver con la ayuda de la comunicación interservicios utilizando colas de mensajería. Para ello utilizamos un broker de mensajes de Azure Service Bus.

¿Qué es Azure Service Bus?

Azure ServiceBus es un broker de mensajes de integración empresarial totalmente gestionado. Azure Service Bus puede desacoplar aplicaciones y servicios y ofrece una plataforma fiable y segura para la transferencia asíncrona de datos y estado. La idea principal es enviar cualquier dato entre los servicios utilizando mensajes. Estos mensajes están en formato binario y pueden contener JSON, XML o incluso texto plano.

Las principales características de Azure Service Bus son las siguientes

  • Envío de mensajes mediante colas. El receptor debe empezar a escuchar alguna cola especial, y si se envía algún mensaje a esta cola – el oyente lo recibirá.No es necesario tener ambas instancias (emisor y receptor) en línea al mismo tiempo. Los mensajes se envían a la cola y quedan a la espera de cualquier oyente que quiera recibir esos mensajes.
  • Temas y suscripciones. Puede crear editores y suscriptores que escuchen algunos temas específicos. Así, un editor puede compartir un mensaje con diferentes receptores (relación 1:n).
  • Programación de la hora. Puede programar un mensaje a una hora determinada, y los suscriptores lo recibirán a una hora programada

Colas

Todos los mensajes se envían a las colas y se reciben de ellas. Usted sólo envía un mensaje a la cola específica, y los mensajes esperarán a un receptor que recibirá y procesará este mensaje. Al final del procesamiento del mensaje, el receptor debe completar el mensaje para eliminarlo de la cola.

Queues

También puede configurar la cola para que el mensaje se complete en la primera recepción de forma automática. En este caso, el mensaje se eliminará tan pronto como el receptor lo reciba.

Temas

Hay una forma más de utilizar los mensajes, que se basa en temas y suscripciones. Puede configurar algunos filtros, el tiempo de vida e incluso condiciones para recibir mensajes en diferentes instancias. Además, diferentes receptores pueden manejar mensajes de un mismo emisor. Un suscriptor puede recibir una copia de cada mensaje enviado al tema, pero los mensajes pueden caducar o autoeliminarse.

Topics

Hemos preferido utilizar colas porque sólo tenemos un servicio (analytics) que debe escuchar cualquier mensaje sobre las actualizaciones de los pedidos.

Implementación de Azure Service Bus

Azure Service Bus es realmente fácil de usar. Podemos implementar esta funcionalidad en unas pocas filas. Pero primero, tenemos que ir al portal de Azure y crear un recurso de Service Bus

Implementing Azure Service Bus

El siguiente paso es rellenar los campos principales: nombre, grupo de recursos y ubicación. Si todo tiene éxito, recibirá una notificación al respecto y podrá ver su espacio de nombres de Service Bus. Para empezar a trabajar con el Service Bus, necesitamos obtener una cadena de conexión. Puede hacerlo haciendo clic en “Políticas de acceso compartidas”. Necesita poner estos datos en el archivo de configuración de su aplicación.

El siguiente paso es crear una cola. Se puede hacer en el portal de Azure.

Implementing Azure Service Bus

En esta etapa, puede configurar su cola. Necesita establecer el nombre de su cola, y puede seguir adelante sin ninguna configuración especial.

Sin embargo, hay algunas cosas importantes que debe saber sobre los valores de configuración:

  • Tiempo de vida del mensaje. Muestra el tiempo que su mensaje podrá ser recibido y procesado. Si su mensaje ha caducado, pasa a la cola de “letra muerta”.
  • Duración del bloqueo. Cuando un oyente recibe un mensaje, dispondrá de cierto tiempo para procesarlo. Durante este periodo, el mensaje estará bloqueado, y nadie más recibirá este mensaje. Si este tiempo transcurre – el mensaje pasa a estar disponible para ser recibido por cualquier instancia que escuche esta cola.
  • Cola de mensajes muertos. Una cosa más que debe saber es que si algún mensaje se recibe diez veces y no se completa, este mensaje se enviará a la cola de letra muerta. Si durante el procesamiento de los mensajes su aplicación lanza un error no manejado, este mensaje será devuelto a la cola.

El primer paso es instalar el paquete Microsoft.Azure.ServiceBus. Puede hacerlo a través del gestor de paquetes NuGet.

Para enviar su primer mensaje a la cola, necesita conectarse a la cola del Azure Service Bus. Se puede hacer de la siguiente manera:

Ahora tenemos que registrar un manejador de mensajes para empezar a escuchar la cola.

Antes de enviar nuestro primer mensaje a la cola, tenemos que preparar un método para procesar los mensajes que se recibirán de la cola. En el código anterior, registramos el método manejador con el nombre “ProcessMessagesAsync”. Vamos a implementar este método de la siguiente manera:

Tenga en cuenta que si no completa el mensaje con el método CompleteAsync, o lo pone en autocompletar, lo recibirá de nuevo.

El último paso es enviar nuestro primer mensaje a la cola.

Después de este paso, puede ir al portal de Azure y ver que el contador de mensajes es ahora superior a cero. Si comprueba su consola, verá que ha recibido un nuevo mensaje de la cola

Como ve, es realmente fácil de usar. No necesita escribir mucho código para implementar la mensajería interservicios utilizando Azure Service Bus. Además, no necesita controlar el procesamiento de sus mensajes. Si algo va mal y recibe una excepción, este mensaje volverá automáticamente a la cola. Más aún, no necesita preocuparse por la recepción de un mensaje infinito (bucle), ya que cuando el mensaje provoca un error varias veces, va a la cola de letra muerta. Después de eso, el mensaje no se recibirá.

Obtendremos el siguiente flujo una vez que se actualice el pedido:

  1. El microservicio de pedidos envía un mensaje con el pedido actualizado a la cola de pedidos.
  2. El microservicio Analytics que está escuchando esta cola recibe este mensaje.
  3. El microservicio Analytics procesa este mensaje, actualizando las entidades relativas al nuevo modelo de pedido y desencadenando el recálculo de Analytics.
  4. El microservicio Analytics recalcula algunos datos analíticos y completa este mensaje.

En este caso, tendremos los datos analíticos reales justo después de la actualización del pedido. Deberíamos implementar el mismo flujo para la creación y eliminación de pedidos.

Ventajas de este enfoque:

  • Podemos sincronizar fácilmente los datos entre los servicios.
  • No necesitamos tener ambos servicios en línea, y podemos simplemente ejecutar el microservicio de análisis mediante un programa para recibir y procesar los mensajes, calcular los datos necesarios y pasar el microservicio al modo de reposo.
  • Si el procesamiento de los mensajes falla, se reenviará automáticamente. No es necesario crear algunas funciones especiales o incluso declaraciones try-catch.
  • El mensaje no se puede perder. Incluso si no puede ser procesado, va a la cola de mensajes muertos, y usted puede controlar fácilmente sus mensajes fallidos.

Notas importantes:

  • Los datos no se sincronizan inmediatamente. Primero van a la cola, luego se reciben y finalmente se procesan. Si necesita que los datos se sincronicen inmediatamente, debería utilizar peticiones directas para actualizar una entidad, pero puede perjudicar el rendimiento y traer algunos problemas adicionales.
  • Debe controlar las instancias de la aplicación que están a la escucha de la cola. Utilice clases singleton para escuchar la cola, o puede obtener un error cuando el mismo mensaje sea recibido varias veces por la misma aplicación.

Cola de mensajes muertos en Azure Service Bus

Cuando obtenga algún error o fallo en el procesamiento de los mensajes varias veces, o su mensaje acabe de expirar, puede ser movido a la cola de letra muerta. Estos mensajes se almacenarán en esta cola hasta que los elimine o los procese. La cola de letra muerta puede enviar mensajes al receptor, y usted puede trabajar fácilmente con estos mensajes como en cualquier otra cola. La única diferencia entre estas colas es el nombre. Si quiere empezar a escuchar la cola de letra muerta, debe utilizar la siguiente sentencia:

Sólo debe pasar el nombre de su cola al método FormatDeadLetterPath de EntityNameHelper y utilizar el resultado como nombre de la cola. Por cada cola que haya creado en Azure Service Bus, hay una cola de Carta Muerta adicional

Además, puede ver la Carta Muerta en Azure Portal sin necesidad de implementar ningún código. Sin embargo, puede utilizar este ejemplo de código para crear, por ejemplo, una función de procesamiento de Dead Letter, que le notificará sobre errores en su aplicación o incluso los resolverá.

Resumen

En algunos casos, no podemos crear microservicios totalmente independientes. En este punto, es posible que necesitemos implementar la comunicación entre los servicios, lo que puede hacerse mediante la mensajería interservicios. Le recomendamos que utilice Azure Service Bus para transferir datos en la aplicación, crear mensajería interservicios y sincronizar los datos entre los microservicios de su aplicación.

Esta característica es realmente fácil de implementar en cualquier aplicación existente. Con la ayuda de este servicio, puede reducir la carga del sistema, ya que su aplicación podrá procesar las tareas una a una, y no al mismo tiempo, como con las peticiones directas.
En la arquitectura basada en microservicios, la comunicación entre los microservicios desempeñará un papel importante en lo que respecta al rendimiento. Así que, en función de sus necesidades, deberá elegir el enfoque adecuado para la comunicación entre servicios.

Vea cómo desarrollamos una solución para la logística de fitness clara utilizando el marco .NET

Este campo es obligatorio.

Section image

uvallie
Oleksandr Kinashchuk

desarrollador .NET en Redwerk