Jun 16

Comunicación Consola Servidor : Hazelcast, Vert.x, REST

Logo HazelcastEn el mismo proyecto del post anterior, estaba replanteandome como hacer que la interfaz de usuario (consola, aplicación java de escritorio) se conecte con el servidor (ejecutable java que no es servidor web ni de aplicaciones). Habitualmente abrimos un socket TCP/IP y definimos la mensajería. Tenemos librerías ya preparadas para esto, es eficiente y lleva muchos años funcionando. Pero a todos nos gusta jugar. Para este proyecto, me estoy planteando usar algún otro tipo de comunicación.

En otros proyectos que he visto (uno de los cuales lo he heredado), usan servicios web REST para todo lo que sea petición/respuesta desde la consola al servidor. Cuando el servidor quiere enviar algo de motu propio a todas las consolas, se usa ActiveMQ como cola de mensajes. Como el proyecto está con Spring Framework, hay soporte para las dos cosas haciendo fácil su codificación. Este mecanismo también está funcionando sin problemas.

Pero lo dicho, quiero seguir jugando.

Lo del servicio REST … ¿podemos eliminarlo usando sólo colas de mensajes o algo parecido? ¿Y en vez de una cola de mensajes ActiveMQ podemos usar algo más sencillo y ligero?

Pues me plantee hacerlo primero todo con Hazelcast. Si pongo modelos compartidos entre consola y servidor y con el mecanismo que tiene Hazelcast de publicación/suscripción a base de topics, quizás me bastaría sólo Hazelcast para reemplazar los web services REST y a ActiveMQ.

Pues no. Por un lado, Hazelcast no ofrece un mecanismo de petición/respuesta. Si uso un topic como petición de forma que el servidor se suscribe a ese topic de petición y cuando la consola quiere algo, publica en ese topic qué quiere, el servidor no tiene forma de responder. Habría que crear un topic temporal de respuesta, de forma que la consola que ha hecho la petición se suscribe a ese topic temporal y recoge la respuesta. Esto lo ofrece ActiveMQ de forma transparente, pero con Hazelcast habría que currárselo.

Y me surgió un segundo tema. Si en base de datos tenemos guardadas una serie de cosas y la consola las quiere, lo normal es pedírselas al servidor y el servidor en respuesta las devuelve. ¿Cómo lo hace en el caso de Hazelcast? Tendría que meterlo en algún tipo de colección de Hazelcast en memoria. ¿Y qué pasa sin son muchos datos?. Pues que hay que cargarlos todos en memoria, o inventar un mecanismo de cargas parciales, con paginados, etc, etc.

Así que descarté el uso exclusivo de Hazelcast. Lo he dejado, pero principalmente porque me vale para el modelo “vivo” de datos. En la aplicación se verá un mapa con barcos moviéndose. Estos barcos moviéndose en lo que llamo modelo “vivo” de datos, los datos que actualmente se presentan en todas las consolas y que el servidor se encarga de ir actualizando para todas. Esto es una ventaja frente a lo que teníamos. Sin Hazelcast (o un equivalente), el servidor tenía que enviar todos los cambios de ese modelo “vivo” a través de eventos por socket TCP/IP o ActiveMQ y las consolas debías actualizar su copia de dicho modelo en base a esos eventos. Con Hazelcast, el servidor toca la colección compartida y la consola ve dicha colección actualizada en todo momento. Es Hazelcast el que se “come” por debajo todo el tema de eventos de cambios del modelo y la actualización en el lado de la consola. La consola puede suscribirse a cambios en esa colección compartida, hazelcast ofrece esa posibilidad, pero para hacer otras cosas que necesite, como borrar el icono del barco en el mapa o desplazarlo, pero no para actualizar esa misma colección de barcos que ya está actualizada

Bien, no me vale Hazelcast para todo. ¿Qué tal Vert.x?. Tiene un EventBus, más sencillo de manejar que ActiveMQ, contempla la petición/respuesta, usa (o puede usar) Hazelcast por debajo por lo que encaja con el Hazelcast que me he planteado usar. Así que eso me planteé. Dejo Hazelcast para el modelo vivo y usar EventBus de Vert.x para peticion/respuesta y publicación/suscripción con Topics.

Me pongo a hacer mis pruebas y … ¡¡Sorpresa!!. Vert.x no garantiza el orden en la entrega de los eventos. Si garantiza que si un publicador envía eventos, un suscriptor concreto los recibe en el orden que el publicador los ha enviado. Pero no garantiza nada más. Si un publicador publica en varios topic y cada topic tiene un suscriptor distinto, los suscriptores pueden recibir los eventos en cualquier orden, no necesariamente en el orden en que el publicador los ha enviado. Y eso me hizo polvo. Para petición/respuesta a veces se necesita que las cosas vayan en orden, que no me contesten antes a lo que he pedido después. Así que que para petición/respuesta descarté Vert.x, seguro que puedo hacer apaños para garantizar el orden, pero va en contra de la filosofía de Vert.x y me parece una fuente importante de bugs si los desarrolladores se despistan.

¿Y para publicación/suscripción con topics, sin respuesta?. Bien, tengo Hazelcast que también lo hace. No voy a meter un framework por encima sólo para eso. Lo dejo aparcado por si en un momento dado Hazelcast se me queda cojo en este asunto y Vert.x me lo solucionara, pero lo dicho, queda aparcado.

¿Cómo hago al final lo de petición/respuesta?. Pues al final he dejado los web services REST.

¿Qué creo que he ganado con todo este cambio aparte de jugar y aprender? Principalmente el tema del modelo “vivo”. La colección compartida de Hazelcast entre consola y servidor me ahorra enviar eventos de cambios en ese modelo en el servidor, recogerlos en la consola y reconstruir en consola con código el mismo modelo que tiene el servidor.

En cuanto a topics, AciveMQ frente a Hazelcast, desde luego es mucho más potente y con más posibilidades ActiveMQ, pero es más complejo y no necesito todas esas posibilidades, tiro de momento por la opción más simple de Hazelcast.

 

Entradas relacionadas:

One Response to “Comunicación Consola Servidor : Hazelcast, Vert.x, REST”

  1. gorlok Says:

    Vert.x tiene (¿o tenía?) la posibilidad de usar múltiples protocolos. Incluso los básicos: TCP y UDP. Si vas a realizar un juego, la mayoría de las veces se termina usando un protocolo binario simple y TCP o UDP, o ambos (para distintas cosas). Me ha tocado hacer servidores de juegos y siempre terminé usando TCP con un protocolo binario. Todo el overhead de REST suele ser inviable en el caso de juegos, salvo algo extremadamente básico. Para los juegos más avanzados, se usa una combinación de TCP+UDP porque incluso las demoras introducidas por el manejo de ventana y retransmisiones de TCP a veces es inviable. Recuerdo que Vert.x traía algunos ejemplos muy básico de TCP y UDP implementados encima de Java NIO.

Leave a Reply