Websockets escalables con Spring y RabbitMQ

Índice de contenidos

1. Introducción

En ciertas ocasiones necesitamos implementar websockets para tener información actualizada en tiempo real con nuestro servidor en nuestras apps y webs. En otros tutoriales de este sitio hemos visto como implementar esto con spring, o directamente contra un ActiveMQ.

En este tutorial vamos a ver cómo implementar la subscripción y envío de mensajes a un WebSocket controlado con Spring bajo el protocolo Stomp, para ver como se configura todo con anotaciones Spring Boot. Usaremos un ejemplo como el del tutorial oficial de spring. Como nuestro WebSocket será utilizado por miles de clientes y ahora nos va la moda de hacer microservicios, vamos a dar un paso más y ver cómo podemos escalar esto y poder enviar mensajes desde cualquier otro microservicio sin importar contra que servidor concreto tienen los clientes abierto el websocket. Para ello utilizaremos RabbitMQ como broker.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (2.2 Ghz Intel Core I7, 16GB DDR3).
  • Sistema Operativo: Mac OS X El Capitan 10.11.6
  • Spring Boot 1.5.7
  • Stomp protocol
  • StompJS

3. ¿Qué vamos a instalar/configurar?

Vamos a implementar una aplicación JEE con Spring Boot que se pueda configurar en clúster para que sea escalable.

Vamos a utilizar el protocolo Stomp para simplificar las comunicaciones y poder utilizar en cliente librerías como StompJS.

Vamos a configurar un RabbitMQ para que se encargue de gestionar las subscripciones de nuestros clientes a través de websockets de tal manera que sea fácil enviar un mensaje a todos los clientes registrados en un topic sin saber contra cuál de los servidores del clúster tienen abierto el socket.

Vamos a ver cómo podemos securizar la subscripción a los topics a través de los websockets.

4. Creación y configuración básica del proyecto

Introducimos en nuestro proyecto Spring Boot la dependencia para poder utilizar websockets:

Configuramos nuestra aplicación para que admita nuevos websockets con STOMP:

Con esto aceptamos nuevos sockets bajo la url “/gs-guide-websocket”, podrán enviar mensajes a urls tipo “/app/*” y subscribirse a topics en urls tipo “/topic/*”.

Creamos nuestro primer “controller” para recibir mensajes a través del websocket a la ruta “/app/hello” con un objeto tipo “HelloMessage” que será automáticamente parseado desde el json que se reciba. Y vamos a enviar un mensaje al topic “/topic/greetings” con un objeto tipo “Greeting” que será parseado a json para ser enviado a través del websocket.

Con un cliente js tipo “StompJS” podemos tener un código sencillo de conexión desde un browser a un websocket, para hacer envío de mensajes y subscribirse a topics para recepción de mensajes.


5. Conectándolo a RabbitMQ

Ya podemos crear websockets pero si escalamos la aplicación los mensajes que enviemos a un topic solo serán recibidos por los clientes que tengan abierto el websocket contra ese mismo servidor.

Vamos a modificar la configuración de spring de websockets de la clase “WebSocketConfig” cambiando la linea ‘config.enableSimpleBroker(“/topic”)’ por:

Para que RabbitMQ soporte STOMP debemos habilitarle el plugin de “rabbitmq_web_stomp”:

Ahora es RabbitMQ el que mantiene el control de que websockets están conectados a que topics por lo que podemos enviar un mensaje a cualquier topic desde cualquier servidor con conexión a rabbitmq. Un ejemplo de envío usando “SimpMessagingTemplate”:

6. Securizando subscripciones

Podemos añadir un interceptor para controlar las subscripciones a distintos topics y securizar éstas. Para ello modificamos la clase “WebSocketConfig”:

El cliente StompJS permite enviar headers para incluir la autenticación. Estos headers pueden obtenerse en el servidor del “message” con:

7. Conclusiones

Hemos visto cómo podemos utilizar WebSockets en nuestra app para tener comunicaciones en tiempo real en un entorno que es escalable y es fácilmente integrable como un microservicio nuevo en nuestro ecosistema, permitiendo a cualquier microservicio el envío de mensajes a los distintos topics de nuestros websockets utilizando RabbitMQ como broker.

8. Referencias