Ir al contenido principal

Lecciones aprendidas de la migración de integraciones: De WSO2 ESB 4.9.0 a EI 6.6.0

Nos planteamos migrar a una versión actualizada de WSO2 Enterprise Integrator una instalación con unas 100 integraciones, que se encontraba en WSO2 ESB 4.9.0, DSS, Api Manager, y Message Broker. Con integración continua CI/CD y servicios desplegados en la nube con servicios gestionados con Kubernetes. Una serie de componentes desarrollados a medida, como conectores, custom mediators, etc.

Parte de los desarrollos realizados recientemente, con un tamaño manejable y siguiendo patrones simples y reproducibles. Otra parte, desarrolladas hace varios años, por diferentes equipos y de un tamaño y complejidad que dificulta el mantenimiento y su evolución.

Adicionalmente se disponía de una serie de scripts de instalación y despliegue, basados en gradle y jenkins, aunque en proceso de migración a gitlab-ci, que también hubieron de ser tenidos en cuenta en nuestro plan.

El proyecto contaba además con una restricción de plazos que nos obligaba a cierta agilidad en el proceso de migración, de un sistema que ya se encontraba en producción.

Primer dilema: ¿a qué versión migramos?

Las dos versiones actualizadas que se plantearon como opciones para la migración de WSO2 fueron Enterprise Integrator 6.6.0 y 7.1.0

Para tomar la decisión con información realista sobre el esfuerzo y dificultad que podía suponer cada opción, se realizaron una serie de pruebas contemplando tanto la adaptación de las herramientas para el despliegue automatizado como de las integraciones.

Las conclusiones de este estudio fueron las siguientes:

En general los ficheros de aplicación CAR que usamos en los despliegues para ESB 4.9.0 eran bastante compatibles con EI 7.1.0, incluyendo elementos del registry, transformadas, gestión de payload json, servicios DSS, llamadas al backend, etc. Eso nos daba confianza en que nuestro proceso de construcción de integraciones no requeriría grandes cambios.

Sin embargo, EI 7.1.0 supone un cambio significativo al estar orientado a microservicios, y por otra parte, la api de administración que usaban nuestros procesos automatizados de despliegue han cambiado significativamente. Por definición los microservicios deberían ser inmutables y por tanto la api de administración no debe poder cambiarlos. En su lugar, debería cambiarse la imagen del microservicio y redesplegarse. Eso suponía un cambio importante para los procesos de despliegue.

Otro problema que presentaba esa orientación a microservicios es que el desarrollo realizado hasta el momento no estaba completamente orientado hacia esa arquitectura, puesto que habían ciertas secuencias o plantillas compartidas, así como ciertos elementos definidos en el registry (plantillas, endpoints, configuraciones, etc.) que también estaban compartidas entre diferentes integraciones.

En el WSO2 ESB 4.9.0 y EI 6.6.0 hay un contexto global compartido que permite compartir ciertos elementos de uso común para las integraciones. Sin embargo, para llevarlo a EI 7.1.0 habría sido preciso realizar un cierto rediseño para dar cabida a esos elementos compartidos en un contexto orientado a microservicios. Esos elementos compartidos habrían tenido que ser desplegados en cada microservicio, lo cual habría obligado a redesplegar todos los microservicios cada vez que se necesitará hacer un cambio en esos elementos comunes, o bien convertirlo en un microservicio en sí mismo, que fuera utilizado por los diferentes microservicios que lo consuman.

Por esas diferencias encontradas en EI 7.1.0, que suponían un mayor riesgo y esfuerzo de migración, y considerando que teníamos una restricción en el tiempo disponible, decidimos hacer la migración de ESB 4.9.0 a EI 6.6.0. En definitiva, no siempre es la mejor opción migrar a la última versión. Es necesario analizar pros y contras de cada opción considerando las circunstancias, desde el punto de vista de un equipo técnico cualificado.

Preparativos de la migración de integraciones

Para la migración de las integraciones se realizó un estudio de los proyectos para determinar la tipología según el patrón de diseño que seguían, y las dependencias que tenían entre ellos para definir el orden a seguir.

Con esta información se elaboró un listado de los proyectos agrupados según su tipología y estructura definida, y se decidió empezar a trabajar en un proyecto de cada una de estas tipologías. De esta forma, pudimos detectar problemas o inconvenientes en fases más tempranas de la migración, y posteriormente replicar las soluciones en el resto de proyectos de una manera más fácil y rápida.

Otro de los estudios que se realizaron fueron las dependencias entre los diferentes proyectos. Existían integraciones comunes que eran transversales y usadas por el resto de las integraciones. También había dependencias directas entre integraciones. Tras revisar dichas dependencias se estableció un orden correcto entre ellas, que nos permitió determinar una estrategia a seguir para acometer cada integración y el ‘roadmap’ de su puesta en producción de una forma más segura, y evitar así conflictos derivados de ello.

El siguiente paso a realizar fue revisar la documentación de WSO2 referente a la actualización de versiones. En nuestro caso, como nos encontrábamos en la versión 4.9.0 del ESB, una versión antigua, y migramos a una versión reciente 6.6.0 del Enterprise Integrator, estuvimos revisando primeramente el paso de nuestra versión del ESB a una versión posterior, y luego el paso de esa versión de ESB al Enterprise Integrator.

  • Esta página le guía a través del proceso de actualización a ESB 5.0.0 desde ESB 4.9.0

Upgrading from a Previous Release – Enterprise Service Bus 5.0.0 – WSO2 Documentation

  • Esta página le guía a través del proceso de actualización a WSO2 Enterprise Integrator (WSO2 EI) 6.6.0 desde WSO2 Enterprise Service Bus (WSO2 ESB) 5.0.0

Upgrading from WSO2 Enterprise Service Bus – WSO2 Enterprise Integrator 6.6.0 Documentation – WSO2 Documentation

Con esta información pudimos determinar los cambios que se habían ido introduciendo  a través de las diferentes versiones, desde componentes del ESB que habían sido desaconsejados en las nuevas versiones, diferentes funcionalidades o comportamientos, etc. Esto nos ayudó a la hora de adaptar nuestras integraciones al nuevo entorno.

También se realizó una revisión de los componentes que habían sido desarrollados a medida para el ESB 4.9.0 (conectores, custom mediators, librerías, drivers de base datos, etc) para determinar qué cambios eran necesarios realizar para adaptarlos al nuevo entorno.

Otra de las tareas realizadas fue la revisión de nuestra integración continua CI/CD, para comprobar qué cambios eran necesarios realizar para el despliegue automático de nuestras integraciones en el nuevo entorno. Para ello contamos con un primer entorno de prueba de Enterprise Integrator 660, donde pudimos realizar las modificaciones necesarias en nuestros scripts de despliegue de despliegue y probarlo a través de nuestra integración continua.

Fases migración de integraciones

Figura 1: Fases migración de integraciones

Minimizar la disrupción

Puesto que se trata de un sistema que se encuentra en producción y muchas de las integraciones son esenciales para el negocio, un objetivo prioritario de la migración fue no causar disrupción al servicio.

Eso por un lado fue facilitado por disponer de la infraestructura en la nube, gestionada con Kubernetes. Por otra parte, hicimos diferentes pruebas de fiabilidad de las operaciones de despliegue para verificar que no habría impacto por realizar la migración mientras el negocio realizaba su actividad. Salvo en contadas ocasiones y más bien por precaución que por una necesidad real, casi todos los despliegues se han realizado en horario de trabajo.

La mayoría de integraciones seguían el patrón de un servicio publicador que expone una API, que a su vez escribe mensajes en un topic, que es recibido por varios subscriptores, que eventualmente transforman el mensaje y lo envían, generalmente llamando a un backend a su destino. Había otras integraciones que seguían un patrón diferente como exponer una API y leer o escribir de un DSS, pero eran casos menos frecuentes, y los manejamos de cara a los despliegues como un publicador.

De cara al análisis diferenciamos entre publicador y suscriptor. Para analizar el impacto, preparamos un proyecto jmeter que generaba una secuencia continua de peticiones, cada petición incluyendo un id secuencial para poder verificar posibles mensajes perdidos o duplicados, que se verificaron revisando los logs de eventos generados en Kibana, y ensayamos diferentes operaciones de despliegue para analizar su impacto.

Para el publisher, el método fiable que se encontró fue seguir nuestro proceso automatizado de despliegue, primero desplegando la integración en EI 6.6.0, y luego desplegando la Api en Api Manager, de forma que el endpoint de Api Manager cambiara de lo desplegado en ESB 4.9.0 a EI 6.6.0. Esa transición llevaba un tiempo mínimo y no produjo ningún impacto de pérdida o duplicado de mensajes, y a lo sumo una mínima demora en el momento de cambiar el endpoint en Api Manager.

Posteriormente, una vez se revisaba el funcionamiento normal en EI 6.6.0, se procedía a eliminar el fichero CAR que estaba desplegado en ESB490. Este mismo procedimiento se siguió para proyectos basados en DSS.

Peligros para evitar

Respecto a los subscriptores nuestras pruebas nos señalaron un par de peligros a evitar:

  • Si desplegábamos en EI 6.6.0 mientras estaba desplegado en ESB 4.9.0, al final habría un topic con dos subscriptores, y los mensajes recibidos se irían repartiendo entre los dos subscriptores.

  • Como los suscriptores siguen un patrón Store and Forward, basado en un message store, eso causaba un serio problema porque un mensaje serializado en una versión del ESB no podía ser interpretado por el EI y viceversa. El message store es un elemento compartido por el ESB y el EI por lo que no teníamos ningún control sobre quien leía y escribía qué mensajes en el message Store, si los dos subscriptores funcionaban simultáneamente.

Solución 

La solución que encontramos para evitar este problema fue:

  • Desactivar la suscripción al topic en el suscriptor del ESB 4.9.0, y esperar hasta que el message store hubiera enviado todos los mensajes al backend y quedara vacío para evitar problemas con la serialización.

  • Borrar el fichero CAR del suscriptor del ESB 4.9.0. De ese modo, la suscripción al topic quedaba inactiva y seguía recibiendo los mensajes del topic que se acumulaban allí.

  • Desplegar la suscripción en el EI 6.6.0. Inmediatamente, se reactivaba la suscripción, y se empezaban a procesar los mensajes allí acumulados, sin problemas de serialización porque en ningún momento el ESB 4.9.0 y el EI 6.6.0 habrían usado concurrentemente el message store.

Con estas operaciones, se consiguió evitar los problemas de serialización, con el mínimo inconveniente de demorar la entrega de mensajes durante el tiempo que se tardaba en desplegar en EI 6.6.0 el nuevo suscriptor.

Problemas detectados

Durante la migración de integraciones nos hemos encontrando con diversos problemas para adaptar y desplegar las integraciones en el nuevo entorno del EI 6.0.0. Algunos de estos problemas han sido derivados de la migración de la versión anterior ESB 4.9.0 a la nueva versión EI 6.6.0, y otros problemas de la nueva infraestructura orientada a contenedores con kubernetes. A continuación se describen con detalle los principales problemas con los que nos encontramos:

Cuando intentamos mover un archivo a un sFTP usando ‘fileconnector’ se produce una excepción si el sistema no puede identificar los permisos de grupo/propietario.

  1. El ‘enrich mediator’ está cambiando la naturaleza de la carga útil de JSON a XML jsonObject aunque el enrich mediator no está relacionado con el body.

  2. El ‘payloadFactory mediator’ falla si se usa funciones inline directamente en la sección de ‘format’.

  3. En ESB490 cuando una petición tiene una cabecera accepts: application/xml y la respuesta es text, está devolviendo text, mientras que en EI660 cuando una petición tiene una cabecera accepts: application/xml y la respuesta es text, está devolviendo un nodo xml <text> con el contenido.

  4. Utilizando la expresión xpath sin la función de texto ‘text()’, se devuelve un nodo xml en lugar del contenido del nodo. Este comportamiento difiere entre las distintas versiones.

  5. Error al procesar los parámetros de la ruta en la solicitud ‘DELETE DSS’.

  6. En algunas integraciones nos encontramos con el problema de que el JSON body desaparece después de una llamada al ‘call mediator’ y no continúa en el flujo de la secuencia.

  7. Como parte de la nueva infraestructura, se ha configurado un proxy istio en kubernetes para el manejo del tráfico de las peticiones entrantes y salientes. En algunas de las integraciones tenemos un servicio proxy para llamar a un backend a través de istio, y cuando el backend es inalcanzable, envía un RST + ACK como restablecimiento de la conexión. Esto provoca un error fatal al gestionar la respuesta en EI 6.6.0.

  8. El proxy istio, en el tráfico de salida, cambia las cabeceras a minúsculas, como es el estándar del protocolo http-2. Esto hace que el EI 6.6.0 falle al intentar manejar el payload recibido como respuesta porque distingue entre mayúsculas y minúsculas.

  9. Nos encontramos con el problema de que mensajes almacenados en una cola del ‘Message Store’ en el ESB 4.9.0, genera un fallo al intentar consumirlos desde el EI600 por un problema de formato de serialización. Esto solo ocurre en el momento del despliegue si ambos suscriptores están operativos.

  10. Problemas con la configuración del ‘timezone’. En ESB 4.9.0 la zona horaria está en formato local, mientras que en la nueva plataforma el EI 6.6.0 está configurado con formato ‘UTC’.

  11. La API de servicios de administración ‘admin services’ cambia de la versión ESB490 a la versión EI660. Sobre todo nos encontramos con el problema que el servicio que usamos en el ESB490 ‘LogViewer Admin Service’ para comprobar logs desde los scripts de despliegue ya no es válido para el EI 6.6.0, debido que en esta versión se usa la versión de 2 de la librería ‘log4j2’ de java, en lugar de la versión 1.

Para gran parte de los problemas detectados ha sido necesario un estudio detallado, y se ha necesitado de la liberación de actualizaciones WUM del EI 6.6.0 por parte del equipo de producto de WSO2 para su resolución. Para otros problemas ha sido necesario aplicar workarounds, o ajustes y cambios en la configuración de la plataforma de kubernetes.

Lecciones aprendidas tras la migración de integraciones /conclusiones

Para hacer una migración de integraciones, es muy importante, al principio del proyecto, analizar en detalle las dependencias entre integraciones y a partir de ahí generar un plan de migración. En nuestro caso, disponíamos de una herramienta que procesa los proyectos, descubre elementos significativos y busca relaciones entre ellos, por lo que nos fue relativamente sencillo obtener esas dependencias, y preparar un plan acorde con ella. Nos encontramos con una integración con un diseño complejo que generaba muchas dependencias y que nos supuso un cuello de botella en el plan que tuvimos que gestionar de una forma cuidadosa. Ese plan debe contemplar que parte de las integraciones se encuentren en el entorno antiguo (ESB 4.9.0) mientras que otras han sido migradas al nuevo entorno (EI 6.6.0).

En un proyecto como este, puede producirse un número importante de imprevistos que son muy difíciles de anticipar. Una buena forma de reducir la incertidumbre es buscar un conjunto de integraciones de diferente tipología, que sea representativa, y hacer unas primera aproximación con ellas para tener una estimación inicial de la complejidad por tipo de integración. En cualquier caso, siempre van a ocurrir imprevistos, y debería haber una previsión de tiempo para este concepto de forma que el proyecto esté protegido ante circunstancias imprevisibles.

Migrar simultáneamente la herramienta de integración (wso2) y la plataforma en la que se encuentra introduce una mayor complejidad, ya que hay demasiadas partes móviles en el proyecto. Es mejor evitarlo, pero con frecuencia es difícil conseguirlo y se aprovecha el cambio de versión para mejorar la infraestructura. En tal caso se requiere una colaboración muy estrecha con los gestores de la infraestructura.

Aunque las versiones supongan cambios que en teoría mantienen la compatibilidad y hay documentos realizando los cambios realizados en cada versión, en realidad hay ciertos cambios sutiles de comportamiento que pueden obligar a retocar las integraciones y adaptarlas.

Es muy importante tener un método de trabajo sistemático que vaya documentando las adaptaciones a realizar para los cambios o problemas conocidos. Con el tiempo llega un momento en que la mayoría de problemas son conocidos y se puede migrar una integración aplicando un checklist, siempre que se tenga la precaución de generar una buena documentación. En nuestro caso, hacia el final del proyecto fue necesario dedicar más recursos al proceso de migración, y prácticamente bastó con entregarles un checklist para tenerlos rápidamente operativos. Para ello fue esencial disponer de una buena documentación.