Recientemente, hemos realizado una migración desde Cloud Composer (Apache Airflow) a Cloud Workflows (servicio serverless de GCP) y los resultados han sido muy satisfactorios. Por ejemplo, hemos logrado ahorrar más de un 90% en el consumo y ahora tenemos un producto más robusto y sencillo.
En este post vamos a ver qué sistemas hay de orquestación en Google Cloud, cuáles eran nuestros problemas con Composer (puede que no sea vuestro caso), cómo migrar de un servicio a otro y nuestras conclusiones.
Seguro que este post os ayudará a tener más opciones a la hora de orquestar vuestros procesos en Google Cloud.
Cuando hablamos de orquestación, a menudo nos viene a la cabeza la automatización de sistemas y servicios de forma coordinada y siguiendo un orden determinado dependiente de resultados anteriores o parámetros cambiantes en cada ejecución.
En un contexto de las arquitecturas orientadas a servicios, la orquestación puede ser sencilla como la ejecución de tareas programadas: envío de mails a un grupo determinado de usuarios, generación de reportes, etc. O, por el contrario, puede englobar un enfoque más complejo como la secuencia de operaciones en múltiples sistemas, esperando que se completen todas las operaciones, provisionando infraestructura de forma dinámica bajo demanda, que se ejecuta durante períodos de tiempo más prolongados y con la capacidad de reaccionar y manejar fallos y reintentos.
Cuando nos movemos hacia el contexto de la ingeniería de datos, la orquestación es fundamental para coordinar los servicios y los flujos de trabajo que preparan, incorporan y transforman los datos. Las tareas a realizar pueden ir más allá del simple procesamiento de datos e involucrar flujos de trabajo complejos que requieran entrenamiento de modelos, aprendizaje automático (ML) y transformaciones complejas a partir de combinaciones de distintas fuentes de datos.
Google Cloud Platform ofrece varias herramientas/servicios gestionados para orquestación:
- Cloud scheduler: orquestación de un único servicio programado en un horario recurrente.
- Workflows: orquestaciones multiservicio complejas durables y stateful.
- Cloud Composer: orquestación de flujos de trabajo basado en Apache Airflow (data workloads).
Algunos ejemplos de cuándo usar cada uno de ellos:
- Cloud scheduler: es una buena opción si solo necesita llamar a un solo servicio a intervalos regulares. Por ejemplo, mandar un evento a Pub/Sub o levantar una Cloud Function.
- Workflows: si necesitas llamar a más de un servicio, usar la salida de uno de ellos como entrada del siguiente o esperar a que termine la ejecución de uno para lanzar el siguiente o utilizar una lógica más compleja: operadores aritméticos y lógicos, matrices, diccionarios, conditional steps …, Workflows es una buena opción.
- Este servicio te permite orquestar llamadas a cualquier API HTTP(s), lo cual incluye no solo cualquier endpoint que hayas expuesto vía Cloud Run o Cloud Functions, sino también los propios servicios de Google Cloud como Cloud Vision AI, BigQuery, Cloud SQL, Cloud Storage, etc.
- Cloud Composer: es la opción si necesitas orquestar flujos de trabajo basados en datos (por ejemplo, ETL/ELT). Al igual que en Workflows se puede crear una tarea para cada step, configurar el orden de las tareas y especificar qué tarea ejecutar a continuación en función de algunas condiciones. El uso más común es para orquestar servicios que componen “Data Pipelines”.
Tanto Workflows como Cloud Composer se pueden usar para la orquestación de servicios con el fin de implementar funcionalidades complejas o realizar procesamiento de datos. Aunque son conceptualmente similares, cada uno está diseñado para un conjunto diferente de casos de uso. En la siguiente sección damos unos tips de cómo podemos saber qué servicio elegir para nuestra implementación.
La verdad es que en parte ambos servicios pueden tener cierto solapamiento, pero la principal diferencia es para qué tipo de arquitectura está diseñado cada producto.
- Workflows: múltiples servicios basados en HTTP en un workflow duradero y stateful, se caracteriza por tener baja latencia y puede gestionar una gran cantidad de ejecuciones.
- Cloud Composer: orquestar workflows basados en datos, data pipelines… Toda la lógica en Cloud Composer, incluidas las tareas y la programación, se expresa en Python como un DAG (Directed Acyclic Graph). Está recomendado para cargas de trabajo por lotes que pueden manejar unos segundos de latencia entre las ejecuciones de tareas.
Para facilitar la selección de uno u otro servicio presentamos la siguiente tabla comparativa:
Workflow orchestrator | Workflows | Cloud Composer |
---|
Sintaxis | YAML o JSON | Python |
Estado | Imperativo | Declarativo (DAG) |
Integraciones | HTTP request Conectores | Operators Sensors |
Triggers/Scheduling | gcloud CLI, Google Cloud console, Workflows API, Workflows client libraries, Cloud Scheduler, Eventrac | Cron-like schedules in the DAG definition file, Airflow Sensors |
Patrones asíncronos | Polling Callbacks Waiting for long-running Google Cloud operations | Polling |
Ejecución en paralelo | ✅ | ✅ |
Latencia | Milisegundos | Segundos |
Vendor Locking | ✅ | Open source (Apache Airflow) |
Modelo de escalado | Serverless | Provisioned |
Pricing | Pago por uso (por step ejecutado) | Basado en la capacidad provisionada |
Procesamiento de datos | No. Depende de integraciones con otros servicios de GCP (ejemplo: Dataprep, Dataflow…). | Sí. Basado en las capacidades de Apache Airflow. |
Si estás interesado en profundizar en el uso de Workflows como herramienta de orquestación te recomendamos que leas este post sobre cómo gestionar Workflows en modo serverless. Podrás profundizar en qué son, sus características y pondrás en práctica tus conocimientos.
Para este post nos hemos centrado en nuestra experiencia en migrar una aplicación completa desplegada en Cloud Composer a Workflows.
Teniendo en cuenta todo lo anterior, nos propusimos migrar nuestros procesos de Cloud Composer a Workflows, por varias razones:
- En primer lugar, estábamos usando Cloud Composer para tareas que aunque estaban relacionadas con pipelines de data (recuperación y enriquecimiento), su principal propósito era iniciar los triggers que desencadenan la ejecución de tareas más pesadas de transformación que realizaban otros servicios. La planificación de las tareas chocaba con las características del servicio, no era necesario mantener el servicio de Composer levantado continuamente, ya que no necesitábamos procesar gran cantidad de datos y no era reutilizable por otros procesos.
- Los costes de la infraestructura provisionada para la naturaleza del servicio nos hacían plantearnos si era rentable seguir manteniendo el servicio tal y como estaba. La realidad era que estábamos usando la infraestructura provisionada para ejecutar un único flujo de trabajo, que habíamos ido simplificando, por unos u otros motivos, a lo largo de la vida del proyecto. Como hemos comentado, el uso de Composer tiene más sentido cuando la infraestructura provisionada es compartida por varios flujos, para optimizar los recursos compartiendo cargas.
- Existían funcionalidades descontinuadas o subflujos sin uso que habían simplificado un flujo de trabajo inicialmente más complejo.
- Necesidad de actualizaciones: versiones, resolución de bugs… que hacían que después de dos años hubiera que darle algo de cariño al mantenimiento del servicio.
- Simplificar todo lo posible el flujo, evitando sobredimensionamiento y ajustar los tiempos de ejecución.
- Mejorar la experiencia de usuario de nuestro blog, ofreciendo siempre recomendaciones adecuadas a nuestros usuarios.
- Y, por qué no decirlo, la aparición de nuevos actores en escena, como Cloud Run Jobs (Preview) que nos ponían en bandeja la migración y las ganas de probar algo nuevo.
Con todas estas razones encima de la mesa nos pusimos manos a la obra. El objetivo del servicio en cuestión es personalizar el contenido de nuestro blog recomendando contenido similar dentro de los propios post. Es decir, mientras se visualiza un post del blog recomendar otros posts similares (puedes ver en este mismo post el “Editor's Picks” a la derecha 😜).
Partimos de un flujo definido en Cloud Composer donde cada DAG tiene como dependencia la salida del anterior: ya sea un fichero, un estado o llamada algún otro servicio. Cada DAG ejecuta una carga de trabajo que está contenerizada y se ejecuta en GKE, lo que nos ha permitido (con mínimos cambios en los Docker files) reutilizar en su totalidad los desarrollos.
Arquitectura de referencia de la que partimos:
Para hacernos una idea del flujo, debajo podemos la interfaz web de Airflow donde podemos ver todos los pasos que se siguen:
No vamos a entrar en el detalle de cada uno de los pasos, pero si es necesario ver cómo llegamos a simplificar este flujo utilizando tres Cloud Run Jobs y dos llamadas HTTP para obtener los mismos resultados.
Analizamos qué pasos era necesario migrar para seguir ejecutando, qué podíamos hacer vía asignación de variables y qué podríamos suprimir (como el aprovisionamiento de infraestructura). Teniendo en cuenta lo anterior la concusión fue:
Como se puede comprobar en la siguiente imagen el objeto de la refactorización fue el motor de recomendaciones “Recommendations engine”, pudiendo mantener el resto de servicios “as-is” y haciendo compatibles ambas arquitecturas para, llegado el día, sustituir un motor de recomendaciones por el otro.
Ahora hablemos de números. A continuación destacamos los aspectos más relevantes en la migración de nuestro servicio de orquestación para desarrollar un motor de recomendaciones:
La estrategia seguida ha sido Replatform. Partíamos de la base de que las aplicaciones ya estaban desarrolladas con frameworks “modernos” y eran portables. Lo que nos ha permitido aprovechar las capacidades nativas de la nube y movernos de manera fácil y rápida hacia un entorno serverless.
Podemos dividir el desarrollo en dos actividades principales:
- Workflows: 60%
- Diseño del flujo de trabajo.
- Creación del entorno (x2).
- Implementación.
- Pruebas e2e.
- Re-configuración & Replatform de cargas de trabajo: 30%.
- Re- configuración mínima de los servicios: nuevas imágenes docker.
- Creación Cloud Run Jobs.
- Integraciones: 10%.
Gracias a que las aplicaciones están desarrolladas con frameworks modernos y que eran portables, el mayor tiempo de migración se lo llevó el diseño y creación del workflow de recomendación. La reconfiguración y replataformado de las aplicaciones fue relativamente sencilla, teniendo que invertir la mayor parte del tiempo en la configuración de container command, variables de entorno, paralelismo de tareas y capacidad necesaria para ejecutar cada carga.
Las integraciones han venido marcadas por la naturaleza del servicio, siendo necesario integrarse con Secret Manager para la gestión de secretos y con un API externo para lanzar los Jobs relacionados con la transformación de los datos gestionados por el servicio. En este caso se han reutilizado todos los servicios, lo que se ha replataformado ha sido la forma en que se dispara la ejecución y la gestión de la recuperación del estado. Esto ha permitido que las integraciones hayan sido straight forward.
En la versión inicial del motor de recomendación se estaban utilizando los siguientes recursos:
- Composer environment (provisioned):
- GKE Cluster 3x nodes: 40GB (The disk size for each VM node in the environment).
- Cloud Composer SQL: default.
- Cloud Composer data storage: default.
Para la versión actual:
- Workflows.
- 3x Cloud Run Jobs:
- Memory to allocate to each container instance: 512.
- Number of vCPUs allocated to each container instance: 1.
Sin tener en cuenta los recursos comunes, vemos que se ha reducido considerablemente el uso de recursos de los que hacemos uso para el motor de recomendación.
Nota: No se han tenido en cuenta los recursos comunes a ambas implementaciones: storage, egress, networking, etc.
- Composer: Para ejecutar el flujo completo tardaba una media de 2h.
- Workflows: Para ejecutar el flujo completo tardaba una media de 19.78 min.
30 días comparando solo servicios de GCP Cloud composer vs Workflows (ver más abajo Nota). Se han reducido en un ~ 96%.
Nota. Tened en cuenta que en esta comparación se ha filtrado por “Servicio” de GCP: Cloud Composer en la primera imagen y Workflows en la segunda imagen. En el caso de Composer, este sería el punto de partida para levantar un entorno de Composer, pero los recursos levantados prácticamente no permiten ejecutar nada más que el entorno y en la mayoría de los casos es necesario ampliar la capacidad del cluster para ejecutar las tareas definidas. Para el caso de Workflows, se ha incluido únicamente el servicio, sin tener en cuenta los Cloud Run Jobs anteriormente mencionados como parte de la ejecución del proceso completo de recomendación.
Para ver una comparación un poco más amplia, en el siguiente punto se incluyen los recursos necesarios a nivel de computación para realizar el flujo de trabajo completo para ambos servicios de GCP.
30 días comparando servicios de GCP Composer vs Workflows y los recursos de computación asociados a cada solución para realizar el flujo de trabajo completo (ver más abajo Nota). Se han reducido en un ~ 98%.
Nota. En este caso la comparación se ha filtrado por “Servicio” de GCP: Cloud Composer y Compute Engine en la primera imagen, y Workflows y Cloud Run Jobs en la segunda imagen. En el caso de Composer, se han incluido los recursos de computación que se utilizan para ampliar la capacidad del cluster y así ejecutar las tareas definidas en el flujo de recomendación. Para el caso de Workflows, se ha incluido el servicio de GCP y los recursos de Cloud Run anteriormente mencionados como parte de la ejecución del proceso de recomendación.
Mirando hacia el futuro los siguientes pasos a corto plazo son:
- Integración con eventrac para detectar eventos en el CMS relevantes para el recomendador
- Mejorar la observabilidad del servicio
Invirtiendo algo de esfuerzo en refactorizar nuestros procesos internos, hemos conseguido modernizar en un tiempo asumible un motor de recomendaciones que es importante para nuestra compañía y en particular para nuestro equipo de marketing para reforzar el engagement de nuestros lectores.
Además de replataformar el motor de recomendaciones, hemos conseguido optimizar el proceso, reduciendo los tiempos de ejecución, los costes, los recursos utilizados y ajustandonos a las buenas prácticas recomendadas. Adicionalmente, hemos podido probar uno de los nuevos servicios de Google en Preview, Cloud Run Jobs, obteniendo muy buenas sensaciones tanto por su facilidad de uso como por su estabilidad y potencial.
Sabemos que no hemos dado mucho detalle de la creación y ejecución de los Cloud Run Jobs, eso lo dejamos para el siguiente post, donde nos centraremos en cómo hemos llevado la creación, integración y ejecución de los mismos. Seguro que estáis deseando leerlo 🙂 .
Tell us what you think.