Un poquito decepcionado con los ESB

esb image  Hace tiempo que oí hablar de los Enterprise Service Bus (ESB) y con ellos he estado jugueteando por mi cuenta algún tiempo, leyendo e informándome en general, hasta que ha llegado la posibilidad de aplicarlo en un proyecto real.

En mi proyecto real, antes de tomar la decisión de si meter o no ESB y cual de ellos meter, decidí hacer algunas pruebas más en serio con los casos concretos que me iba a encontrar.

El primer punto son sockets TCP/IP con protocolo propio, es decir, mensajes binarios con su propia cabecera y forma de delimitar los mensajes dentro del flujo de bytes que es un socket TCP/IP. Mi primera opción de ESB, por supuesto, los gratis y más conocidos, en concreto, Apache Servicemix, Así que con él voy a hacer la prueba. Lo primero, es que si el protocolo es binario y no un simple protocolo de texto delimitado por retornos de carro, te tienes que hacer una clase java que sea capaz de hacer este trabajo por Apache Servicemix. De acuerdo, me puse a ello y conseguí hacerla…. pero me costó un buen rato de investigación. La documentación es escasa y en ningún sitio pone cómo hacerlo. Al final rebuscando por los ejemplos y fuentes del propio Apache Servicemix encontré cómo hacerlo. Esa ha sido mi primera pega/decepción con este ESB, la documentación es bastante pobre.

Y una vez conseguido, me pongo a probar y me encuentro una segunda pega. Un ESB implementa los Enterprise Integration Patterns (EIP), Y en ellos, hay dos posibles flujos de mensajes: En los que uno sólo envía y el otro sólo recibe, es decir, una única dirección, o bien los petición/respuesta, es decir, uno pide y el otro responde, por cada mensaje de ida debe haber uno de vuelta. Y eso a mí no me vale, en mi proyecto necesito que cualquiera de los dos lados, de modo espontáneo, puedan enviar o recibir, sin necesidad de haber enviado o recibido previamente una petición.

Bien, podría convivir con eso y seguramente encontraría algún tipo de solución.

Y se me ocurre probar lo que en EIP se llama controlbus, es decir, la posibilidad de parar y re-arrancar un flujo de datos a voluntad. Pues bien, Apache Servicemix lo soporta, da métodos start y stop para parar definitivamente el canal y pause/resume para pararlo temporalmente. Casualmente, con el componente camel-netty (que es el que nos proporciona socket TCP/IP), no funciona el suspend/resume. 🙁

Y finalmente, decido hacer otra prueba que también necesito, socket multicast. Pues bien, aunque teóricamente están soportados por Apache Servicemix, no es cierto, símplemente no funcionan. Hay dos componentes que nos pueden dar esta funcionalidad: camel-mina y camel-netty. Camel-Mina directamente dice que no lo soporta. Camel-netty sí, pero si lo pones, salta una excepción de "bind" y no funciona. Y no, no es que el puerto ya esté ocupado. Te pones a rebuscar en el código de camel-netty y ves que el test de JUnit que verifica el multicast directamente está deshabilitado. Y si lo habilitas, falla.

Así que decido pasar de Apache Servicemix, ya que me está dando demasiados problemas: falta de documentación para tus propios desarrollos, no funcina multicast… 

Y me busco otro ESB gratis, voy por jboss-fuse, y lo descarto casi inmediatamente. Tanto Apache Servicemix como JBoss Fuse se basan por debajo en la librería apache camel y la documentación de jboss es casi una copia de la de Servicemix. Así que mismos problemas … con uno añadido. Una de las cosas que aporta Jboss fuse en un eclipse "tuneado" para Jboss fuse, que permite definir gráficamente las rutas que quieres crear en el ESB… y que falla más que una escopeta de feria al menos con el componente camel-netty. Pongo el componente gráfico, relleno los formularios que salen …. y en el xml por debajo me genera mal la URL del punto de conexión. La arreglo a mano, y en cuento me descuido, me la vuelve a estropear.

Así que voy por otro ESB. El siguiente en la lista es Mule ESB. Este está mucho más guay, mucho mejor documentado, mis pruebas fueron bien a la primera, sin demasiada complicación …. pero me da la impresión de que es un ESB de pago. Creo que  me he bajado el trial de 30 días….

Con todo esto, ya casi he desistido de poner un ESB en el proyecto. Voy a darle un vistazo a wso2, que tiene muy buena pinta, la documentación parece buena y tiene pinta de ser gratis. A ver qué tal.

He visto por encima otros como OpenESB, Talend, y Synapse, pero son quizás menos conocidos y en todos ellos, mirando por encima la documentación, he visto alguna cosilla que no me acaba de convencer.

Estoy seguro que los ESB funcionan bien, ya que son bastante conocidos y aparentemente muy usados. Pero me da la impresión de que funcionan muy bien si te atienes a los protocolos para los que están pensados, en concreto y sobre todo, Web Services, JMS, HTTP, FTP, etc.

ESB vs MQ vs DDS

Ando últimamente mirando herramientas estilo Enterprise Service Bus (ESB), de colas de Mensajes (MQ) y Data Distribution Systems (DDS). La primera vez que oyes hablar de ellas te preguntas ¿qué son exactamente? ¿Para que sirven?. La primera explicación que encuentras en la Web de cualquiera de ellas es la habitual : "Una herramienta maravillosa que con poco trabajo te resuelve todos tus problemas y te va a hacer el más feliz de los programadores". Si profundizas un poco más, llegas a las definiciones técnicas que nadie entiende, como "Es la implementación del estándar JSR x33, bájate y lee el estándar de dos mil páginas para saber de qué estamos hablando".

Aquí va un "pequeño" resumen de qué son y para qué sirven, según lo he entendido tras andar investigando y jugando con algunas de ellas.

¿Cual es el problema que pretenden resolver?

Todas ellas pretenden resolver más o menos el mismo problema, pero lo hacen con diferentes aproximaciones, siendo más o menos intrusivas en nuestro desarrollo.

Imagina un sistema complejo en el que varios ejecutables están corriendo en varios ordenadores. Estos ejecutables colaboran entre sí enviándose mensajes unos a otros, compartiendo datos, repartiendo tareas, etc. El esquema podría ser similar al de la siguiente figura, donde hay tres ordenadores (las cajas cuadradas), con siete ejecutables A,B,C… y las comunicaciones entre ellos

Problema que pretende resolver ESB, MQ y DDS

Cada ejecutable conoce a los demás ejecutables con los que está trabajando y establece las conexiones que necesita para colaborar con ellos. Esta aproximación tiene varios problemas:

  • Cada ejecutable debe saber las IP/hosts y puertos donde están los otros ejecutables con los que colabora
  • Los ejecutables deben ponerse de acuerdo en el formato en el que se envían los datos.
  • Si más adelante queremos ampliar o modificar el sistema añadiendo, quitando o moviendo de sitio ejecutables, tendremos que tocar todos los ejecutables afectados. Por ejemplo, imagina que añadimos un cuarto servidor con ejecutables H y J que quieren colaborar con algunos de los ya existentes, casi seguro que tendremos que tocar los ya existentes para que admitan a los nuevos.
  • ¿Y qué pasa si alguno de esos ejecutables existentes no podemos tocarlo porque es un producto comercial, nos lo hizo otra empresa o se ha ido el desarrollador que lo concoce? (triste, pero real como la vida misma, a veces se va el que lo ha hecho y nadie más se atreve a tocarlo).

Dar flexibilidad a este tipo de montajes y facilitar la conexión con nuevos ejecutables es lo que pretenden resolver todo este tipo de herramientas ESB, MQ y DDS. Empezamos a ver la solución que propone cada una de ellas, empezando de la menos intrusiva (la que nos oblgaría a hacer menos cambios en nuestros ejecutables ya existentes) a la más intrusiva (que nos obligaría prácticamente a diseñar el sistema pensando en ella).

Enterprise Service Bus (ESB)

 Hay varias herramientas gratuitas de este tipo, como Apache Service Mix, Mule ESB, JBoss Fuse, WSO2 Enterprise Service Bus.La solución que proponen estas herramientas es arrancar uno o varios ejecutables ESB de forma que todas las aplicaciones se conecten al ESB en vez de unas con otras. Es en este ESB donde configuramos las rutas de las conexiones, diciendo por ejemplo, que lo que mande el ejecutable A se debe enviar al ejecutable B. El esquema sería parecido al siguiente

Enterprise Service Bus

Las bondades de esta solución son las siguientes

  • En el ESB se establecen las rutas de qué ejecutables hablan con qué ejecutables. De esta forma, el conocimiento de qué ejecutables hay y dónde están queda centralizado en el ESB, en vez de repartido por los distintos ejecutables de nuestra aplicación.
  • Estas rutas se pueden crear, modificar y eliminar en caliente, por lo que sería posible, por ejemplo, añadir un nuevo ejecutable a nuestro sistema y establecer las rutas en caliente para que este ejecutable sea capaz de enviar/recibir de los que ya están arrancados.
  • Las rutas pueden tener "inteligencia", de forma que pueden enviar un mensaje procedente de un ejecutable a varios ejecutables a piñón fijo, o bien seguir algún tipo de criterio para decidir a cual enviarlo, filtrar para enviar unos mensajes sí y otros no, etc, etc. Por supuesto, esta "inteligencia" se puede cambiar en caliente.
  • Como parte de la "inteligencia", las rutas pueden modificar los mensajes, siendo uno de los casos más habituales el cambio de formato de mensaje. Si un ejecutable usa el protocolo FTP y el otro HTTP, la ruta podría hacer la conversión correspondiente para, por ejemplo, coger ficheros de un servidor FTP y subirlos a una web con HTTP o al revés. Si los protocolos son estándar (FTP, HTTP, SNMP, XML, …) los ESB saben tratarlos y convertir entre ellos. Si no son estándar, podemos añadir nuestro trozo de código dentro del ESB para hacer las conversiones a nuestro gusto.
  • Otra ventaja adicional es que estas herramientas permiten de alguna forma monitorizar las rutas, de forma que podemos ver qué mensajes pasan por ellas, si se utilizan o no, si hay fallos, etc.
  • Las posibilidades que implementan las rutas suelen conocerse como "Enterprise Integration Patterns" o EIP. Siguiendo el enlace puedes ver todos estos patrones que suelen implementar.

Este es el mecanismo menos intrusivo porque nuestros ejecutables siguen siendo tal cual y enviando/recibiendo los mensajes en los formatos que ya tienen. Únicamente debemos cambiar la IP/host de conexión para que sea contra ESB en vez de unos con otros y nos queda el trabajo de configurar rutas en el ESB y darles la lógica que sea necesaria (conversiones de datos, filtros y en general cualquier EIP de la lista anterior).

Colas de Mensajes MQ

 Hay varias herramientas de colas de mensajes gratuitas, siendo ActiveMQ posiblemente la más conocida. Otras son RabbitMQ o Apache Kafka. La solución planteada es similar a ESB en el sentido de que debemos arrancar uno o más ejecutables MQ y nuestras aplicaciones deben conectarse a ellos. Sin embargo, es más intrusiva que ESB en el sentido de que debemos conectarnos con el protocolo que establece MQ, no podemos seguir conectándonos usando nuestros propios protocolos.

A MQ le enviamos mensajes en el formato que admite y cualquier otro ejecutable que tenga interés puede recibirlos. El esquema de trabajo sería como el siguiente

 Message Queue

Dentro de MQ se definen "topic" y "queue" con nombres, tantos como queramos. Los ejecutables envían mensajes a estos topic o queue. Otros ejecutables se suscriben a estos topic y queue de forma que recibirán los mensajes. La diferencia entre un topic y un queue es que un topic entregará sus mensajes a todos los ejecutables que se hayan suscrito, mientras que un queue sólo lo entregará a uno de los suscriptores. Un queue se utiliza más como un reparto de tareas.

Esta aproximación me parece más sencilla y elegante que la de los ESB, pero tiene el inconveniente de que nuestros ejecutables deben estar pensados para enviar y recibir mensajes a MQ, por lo que puede ser un trabajo modificar un ejecutable existente para adaptarse a MQ.

O quizás no. Los ESB suelen entender los mensajes de los MQ, de hecho, Apache Service Mix (un ESB) lleva integrado ActiveMQ (un MQ) Nuestra aplicación puede conectarse con su protocolo normal contra ESB y en ESB podemos establecer una ruta para convertir los mensajes en el formato de la aplicación a mensajes en el formato de MQ y enviarlos a MQ. Por otro lado, en otro sitio, haremos una ruta que recoja estos mensajes MQ, los convierta al protocolo que necesite la aplicación receptora y se los despache en el formato que ella entienda.

 Data Distribution Service DDS

De este tipo de aplicaciones hay menos gratuitas, pero tenemos por ejemplo OpenDDS y OpenSplice DDS. El concepto aquí es similar a las MQ, pero va más allá. Debemos arrancar uno o más ejecutables DDS y nuestras aplicaciones deben conectarse a ellos. La diferencia con MQ es que en DDS debemos definir todos nuestros tipos de datos y nuestros datos. Por ejemplo, si nuestra aplicación controla una flota de camiones, debemos indicar a DDS que tenemos un tipo camión con los campos matrícula, carga máxima, año de fabricación, modelo, marca, etc. y debemos indicar a DDS que vamos a tener una lista de camiones en revisión, una lista de camiones en recorrido, etc, etc.

A partir de aquí, nuestros ejecutables se conectan a DDS y en formato DDS van alimentando estos datos. Cualquier ejecutable puede a su vez suscribirse a los datos para enterarse de cambios en ellos. El esquema sería el siguiente

Data Distribution Service DDS

Esta solución como se puede intuir es la más intrusiva de todas, ya que no solo nos obliga a adaptarnos al protocolo de DDS, sino que de alguna forma dejamos en DDS la responsabilidad de mantener nuestros datos. Hasta cierto punto, DDS hace las veces de una base de datos (de hecho, suele tener una base de datos detrás que respalda nuestros datos), pero con la posibilidad de suscribirse a cambios. DDS suele además poder trabajar "distribuido". Varios ejecutables DDS interconectados entre sí, de forma que si metemos datos por uno de ellos, podemos retirarlo en cualquiera de los otros.

La principal ventaja de DDS es que está pensado para ser muy eficiente, por lo que no es raro encontrarlo en sistemas de tiempo real, defensa , espacio, transporte.