Orquestando Flujos de Datos en Lyft: Comparando Flyte y Airflow

Kevin Jevin Woo
Lyft Engineering en Español
20 min readNov 1, 2023

Introducción

En una empresa impulsada por datos como Lyft, los datos son la columna vertebral de muchos componentes de la aplicación. El análisis de datos nos proporciona incentivos para mejorar las características existentes y crear nuevas. Hoy en día, Lyft recopila y procesa alrededor de 9 billones de eventos analíticos al mes, ejecutando aproximadamente 750,000 tuberías de datos y 400,000 trabajos de Spark utilizando millones de contenedores.

En presencia de trabajos de computación en motores como Spark, Hive, Trino, y grandes cantidades de código Python para procesamiento de datos y ML frameworks, la orquestación de flujos de trabajo se convierte en un desafío complejo. La orquestación es el mecanismo que combina tareas de computación y las ejecuta como un flujo de datos, donde dicho flujo de datos generalmente se representa como un grafo.

Ejemplo de un flujo de dato

Es importante tener en cuenta que la orquestación no es la computación como tal. Por lo general, orquestamos tareas que se ejecutan en clústeres de cómputo externos.

Históricamente, Lyft ha utilizado dos motores de orquestación: Apache Airflow y Flyte. Flyte, creado y lanzado como proyecto de código abierto por Lyft, es ahora un proyecto top level de la Fundación Linux.

En Lyft, utilizamos Airflow y Flyte: los ingenieros pueden elegir el motor que mejor se ajuste a sus requisitos y casos de uso.

Tanto Flyte como Airflow son piezas esenciales de la infraestructura en Lyft y tienen mucho en común:

  • Soportan Python para escribir flujos de trabajo.
  • Ejecutan flujos de trabajo de manera programada o ad hoc.
  • Ofrecen integraciones con motores de cómputo.
  • Funcionan bien para procesamiento por lotes, pero no son adecuados para el procesamiento en tiempo real (stream processing).

Compartimos nuestras experiencias con Airflow y Flyte en publicaciones anteriores. En esta publicación, nos concentraremos en comparar su implementación en Lyft. En primer lugar, nos sumergiremos en la arquitectura y resumiremos sus ventajas y desventajas. Luego, explicaremos por qué Lyft decidió crear Flyte a pesar de ya haber adoptado Airflow. Por último, compartiremos nuestros pensamientos sobre los patrones y antipatrones de cada motor y proporcionaremos ejemplos de casos de uso.

Esperamos que esta información te ayude a elegir el motor adecuado en función de los requisitos y particularidades de tu caso de uso.

Airflow

Apache Airflow es un motor de orquestación que permite a los desarrolladores escribir flujos de trabajo en Python, ejecutarlos y supervisarlos. Hoy en día, Airflow es una de las piezas esenciales de nuestra infraestructura. Lyft es uno de los primeros usuarios de Airflow, y hemos contribuido con varias adaptaciones, mejoras de seguridad y herramientas personalizadas.

Los principales problemas que Airflow resuelve en Lyft son la orquestación de ETL al coordinar consultas SQL en motores de cómputo como Hive y Trino.

Conceptos de Airflow

Para tener un mejor contexto, aquí hay algunos conceptos clave de Airflow:

  • Tarea: una unidad de computación. Las tareas dentro de un DAG pueden ejecutarse secuencialmente o en paralelo.
  • DAG: grafo acíclico dirigido, un flujo de trabajo compuesto por tareas y dependencias entre ellas.
  • Operador: el arquetipo de una tarea; por ejemplo, una ejecución en Python / Bash o una integración con un motor de cómputo como Hive o Trino.
  • Sensor: una subclase del operador responsable de realizar el seguimiento de una fuente de datos y desencadenar la ejecución del DAG. El sensor más popular en Lyft es el sensor de particiones, que verifica las tablas de Hive y se activa cuando se agrega una nueva partición de datos.

El sensor de particiones realiza un seguimiento continuo de la tabla “event_rides” y se activa cuando aparecen los viajes del día anterior. Luego, se calculan las estadísticas de los viajes y se almacenan en la tabla STAGE. Después de verificar la corrección de los resultados, los datos se intercambian con la tabla PROD anterior.

Por favor, consulta la documentación para obtener un contexto más detallado sobre Airflow y una lista completa de operadores.

Arquitectura de Airflow en Lyft

Como se muestra en el diagrama anterior, los componentes principales de la arquitectura son:

  • Agendador: ejecuta DAGs, los envía al ejecutor y registra todas las ejecuciones completadas en la base de datos de metadatos.
  • Servidor web: una aplicación web que permite activar DAGs, ver su estado e historial de ejecución.
  • Ejecutor Celery: colas de mensajes y múltiples workers que ejecutan tareas como procesos separados.

En Lyft, utilizamos Apache Airflow 1.10 con un ejecutor basado en una cola de tareas distribuida de Celery. Este es un planificador de lotes centralizado y monolítico con múltiples trabajadores que pueden escalar horizontalmente. Todas las máquinas deben tener un conjunto idéntico de bibliotecas con versiones similares. Es importante destacar que los trabajadores ejecutan tareas como procesos separados en las mismas máquinas. Compartimos nuestra experiencia relacionada con la versión 1.10 de Airflow en este artículo, ya que aún estamos en proceso de migrar a la versión 2.0+.

Beneficios de Airflow

Airflow es una herramienta fácil de aprender y rápida de comenzar a usar. Cuenta con una amplia comunidad de código abierto y una buena documentación. Airflow tiene una interfaz web simple e intuitiva. Vale la pena mencionar la gran cantidad de operadores disponibles. Otro gran beneficio es el buen soporte para tareas de detección de tablas.

Desventajas de Airflow

A continuación, puedes encontrar las desventajas de Airflow que consideramos más significativas:

  • Airflow carece de un aislamiento adecuado de bibliotecas. Se vuelve difícil o incluso imposible si algún equipo requiere una versión específica de una biblioteca para un flujo de trabajo determinado. Además, en el caso del aprendizaje automático (ML), a menudo ocurre que los equipos crean sus propias bibliotecas y las reutilizan en varios proyectos y flujos de trabajo, como el entrenamiento y el despliegue de modelos, lo que significa que todos los flujos de trabajo deben ejecutar la misma versión de esa biblioteca.
  • No hay forma de limitar el uso de recursos por tarea, y los trabajadores no están aislados del código del usuario. Por lo tanto, las tareas intensivas en recursos pueden abrumar al trabajador e impactar negativamente a otras tareas. Las tareas pesadas también pueden detener el progreso de otros flujos de trabajo, ya que un grupo fijo de trabajadores puede estar completamente consumido.
  • Airflow no admite el versionamiento de DAGs: siempre se observa la versión más reciente. Por lo tanto, es imposible ejecutar la versión anterior en caso de problemas o comparar resultados de diferentes versiones.
  • No hay forma de separar los DAGs en entornos de desarrollo, staging y producción utilizando los atributos estándar de Airflow de Airflow. Esto dificulta el uso de Airflow en aplicaciones críticas que requieren pruebas adecuadas y la capacidad de retroceder a versiones anteriores de los flujos de trabajo en caso necesario.

Además, vale la pena mencionar algunos matices:

  • En Lyft, todos los DAGs se envían a la misma instancia de Airflow, y el espacio de trabajo lógico se comparte entre todos los equipos. Hay equipos que trabajan con datos sensibles y tienen requisitos de seguridad específicos. La separación de los límites de seguridad solo es posible mediante el mantenimiento de un conjunto separado de trabajadores con roles de IAM diferentes. Al asignar siempre trabajadores separados, se dificulta mantener un aislamiento de permisos más granular por caso de uso.
  • Airflow no gestiona el flujo de datos entre tareas; la secuencia de tareas debe definirse explícitamente. Como Airflow no es consciente de los datos, es difícil implementar el almacenamiento en caché, ya que no hay soporte para ello. Por último, Airflow está diseñado solo para Python y no permite escribir flujos de trabajo en otros lenguajes.

Flyte

Flyte es una plataforma de automatización de flujos de trabajo para procesos complejos y críticos a escala de datos y aprendizaje automático (ML). Actualmente, Flyte está siendo desarrollado activamente por una amplia comunidad, por ejemplo, Spotify ha contribuido al SDK de Java.

Apache Airflow es una herramienta adecuada para ETL y no existen razones para reinventarla. El objetivo de Flyte no era reemplazar a Airflow, sino complementar el ecosistema de herramientas de la empresa. Había clases de problemas en las que nos encontrábamos limitados al utilizar Airflow:

  • Casos de uso que requieren código personalizado en Python, Spark o frameworks de ML, lo que implica una computación intensiva en recursos y la necesidad de utilizar bibliotecas personalizadas. Las versiones de las bibliotecas pueden variar entre equipos.
  • Capacidad para ejecutar cálculos pesados sin impacto en otras tareas.
  • Capacidad para retroceder y ejecutar una versión anterior del flujo de trabajo para comparar los resultados e inspeccionarlos.
  • Soporte para el almacenamiento en caché de resultados para acelerar la ejecución del flujo de trabajo y reducir costos.

En Lyft, Flyte se utiliza para tareas que requieren bibliotecas personalizadas y aislamiento de cómputo, como trabajos intensivos en recursos en Python, Spark y frameworks de aprendizaje automático (ML).

Conceptos de Flyte

Para un mejor contexto, aquí hay algunos conceptos clave de Flyte:

  • Tarea: una unidad de ejecución que tiene un entorno aislado con bibliotecas y paquetes. Las tareas pueden ser código en Python, trabajos distribuidos de Spark, llamadas a un motor de cómputo como Trino o Hive, o cualquier ejecución de contenedor Docker.
  • Flujo de trabajo: un conjunto de tareas y las dependencias entre ellas.
  • Proyecto: un conjunto de flujos de trabajo.
  • Dominio: una separación lógica de flujos de trabajo en el proyecto: desarrollo, staging, producción.
  • Plan de lanzamiento: una instancia de un flujo de trabajo que se puede programar con cron y puede utilizar una entrada preconfigurada.

Un ejemplo de flujo de trabajo compuesto por dos tareas de Spark (“agregación de viajes” y “agregación de telemetría”) que agregan datos y generan una salida para el entrenamiento del modelo. La tarea de entrenamiento del modelo contiene un código personalizado en Python y la biblioteca XGBoost empaquetada como una imagen de Docker. El resultado final es el artefacto del modelo.

Las entradas y salidas de los flujos de trabajo y tareas siguen un esquema de tipos fuertemente definidos. Flyte detecta automáticamente las dependencias entre tareas en función de las entradas y salidas, construye gráficos de dependencias y decide automáticamente ejecutar tareas de forma secuencial o en paralelo (cuando usamos Airflow, debemos definir explícitamente la secuencia de ejecución). Tener interfaces de tipos fuertes permite lograr interoperabilidad entre tareas o flujos de trabajo creados por diferentes equipos.

Para obtener más información sobre Flyte, sus características y casos de uso, consulta la documentación de Flyte.

Arquitectura de Flyte en Lyft

Flyte toma cierta inspiración de Airflow pero tiene algunas diferencias. Flyte agrega una capa lógica en la parte superior de Kubernetes para permitir ejecuciones grandes y con estado. Flyte es responsable de solicitar recursos y ejecutar cálculos, por ejemplo, crear nuevos pods o clústeres de Spark. Kubernetes se encarga de la ejecución de tareas y el aislamiento de recursos. La infraestructura es efímera: se crea desde cero por cada ejecución de tarea y luego se termina.

La arquitectura de Flyte se basa en operadores de Kubernetes y “custom resource definitions” (CRD). Un buen ejemplo es Spark en Kubernetes.

Como se muestra en el diagrama anterior, los principales componentes de la arquitectura son:

  • Administrador de Flyte: un servicio que registra y almacena los flujos de trabajo en la base de datos de metadatos. Al activar una ejecución, crea recursos de flujo de trabajo de Flyte (custom resource definitions, CRDs) en el clúster de Kubernetes y registra el historial de ejecución.
  • Propulsor de Flyte: un operador de Kubernetes que consulta la API de Kubernetes en busca de recursos de flujo de trabajo de Flyte recién creados (CRD) y lanza pods u otros operadores como Spark. También maneja fallos y reintentos, y realiza control de velocidad y encolamiento si el clúster de Kubernetes carece de recursos.
  • Tablero de Flyte: una interfaz web que permite activar flujos de trabajo y ver el estado de ejecución.
  • Almacenamiento de objetos en la nube: almacena las entradas y salidas de las tareas y las definiciones de esquema. A diferencia de Airflow, Flyte no utiliza una base de datos relacional para este propósito para evitar un cuello de botella. En Lyft, utilizamos AWS S3.

En Lyft, utilizamos múltiples clústeres de Kubernetes para aislar los dominios de fallos y así poder escalar. Flyte Admin permite este modo de forma nativa.

Beneficios de Flyte

El principal motivo para adoptar Flyte fue abordar algunas carencias fundamentales en Airflow que eran importantes para nosotros.

La ventaja más significativa de Flyte es el aislamiento del entorno y las dependencias. El código y las bibliotecas se empaquetan en una imagen de Docker. Este enfoque permite tener diferentes bibliotecas con diferentes versiones por equipo, e incluso hacerlo para una tarea específica. El proyecto se divide lógicamente en dominios: development, staging y producción. Los dominios permiten promover el código a producción de manera gradual siguiendo prácticas de desarrollo como CI/CD, pruebas unitarias/integradas y revisión de código.

Kubernetes permite definir cuotas de recursos y lograr un adecuado aislamiento de cómputo. Las tareas que requieren muchos recursos no afectan negativamente a las demás y no ponen en riesgo la estabilidad de todo el planificador. Flyte es una buena elección si tus tareas tienen requisitos específicos de recursos, como GPUs: Kubernetes dirige dichas tareas a los nodos que admiten GPUs. Además, podemos lograr un aislamiento adecuado de permisos entre los flujos de trabajo de Flyte: Kubernetes admite el concepto de cuenta de servicio y nos permite asignar roles IAM específicos por pod.

Una característica convincente de Flyte es la versionabilidad de los flujos de trabajo: creamos una nueva imagen de Docker con una nueva versión del código y las bibliotecas, y registramos una nueva versión del flujo de trabajo. Podemos ejecutar cualquier versión en cualquier momento: esto nos brinda una gran ventaja para la solución de problemas, revertir cambios y comparar resultados entre diferentes versiones (hacer pruebas A-B). La capacidad de utilizar dominios y la versionabilidad de los flujos de trabajo hacen de Flyte una buena elección para aplicaciones críticas donde los cambios deben ser probados y desplegados sin importar los flujos de trabajo que se estén ejecutando actualmente.

Actualmente están disponibles los SDK de Python y Java para escribir flujos de trabajo. Sin embargo, interesantemente, Flyte compila los flujos de trabajo y los almacena en una representación independiente del lenguaje, lo que nos permite contribuir con un nuevo SDK y potencialmente agregar soporte para cualquier lenguaje a través de contenedores sin procesar. Flyte es perfecto para flujos de trabajo heterogéneos: podemos empaquetar cualquier ejecutable binario como una imagen de Docker y convertirlo en una tarea, lo que nos brinda la flexibilidad de elegir cualquier lenguaje para el desarrollo o cualquier biblioteca o marco de trabajo.

Vale la pena mencionar otros beneficios de Flyte, como registrar y ejecutar flujos de trabajo a través de la API y la capacidad de almacenar en caché los resultados de las tareas. La capacidad de comprender los datos nos permite concentrarnos en la lógica del negocio y permitir que Flyte construya un grafo de dependencias para nosotros.

Desventajas de Flyte

Las desventajas más significativas de Flyte están relacionadas con el costo:

  • El aislamiento del entorno y las dependencias en Flyte conlleva un costo: los equipos necesitan mantener un repositorio, imágenes de Docker y actualizar bibliotecas. Algunos equipos prefieren no hacer este esfuerzo y encuentran que Airflow es más fácil de usar.
  • Flyte crea infraestructura efímera en Kubernetes. La creación de infraestructura aislada y efímera bajo demanda involucra costos adicionales de tiempo al iniciar nuevos pods y es excesivo para tareas o trabajos pequeños. Esto es un compromiso: el costo de crear un clúster efímero frente al mantenimiento de un clúster independiente. No parece ser un problema de Flyte, sino más bien un patrón no recomendado. Por cierto, la comunidad de Flyte está trabajando en una actualización que permitirá reutilizar pods entre tareas y flujos de trabajo. Esto nos permitirá ejecutar cargas de trabajo pequeñas con menor latencia.

Actualmente, Flyte no tiene tantas integraciones como Airflow, lo que puede requerir más trabajo manual para escribir código personalizado.

Airflow vs. Flyte: cómo elegir la herramienta adecuada para tu caso de uso

Lyft es un usuario intensivo de Airflow y Flyte: actualmente, tenemos más de diez mil flujos de trabajo únicos y alrededor de un millón de ejecuciones al mes. Proporcionamos guías y alentamos a los equipos a utilizar la herramienta recomendada en función de las características de sus casos de uso. En Lyft no tenemos reglas estrictas sobre cuándo usar Airflow o Flyte, ya que puede haber muchas otras razones detrás de las decisiones del equipo, como el uso histórico o la experiencia en una herramienta en particular.

Cuándo usar Airflow

Apache Airflow es una buena herramienta para ETLs que utilizan un conjunto estándar de operadores y orquestan sistemas de terceros cuando no se requiere un entorno personalizado y aislamiento de cómputo.

Sin embargo, reconsidera el uso de Airflow si tu flujo de trabajo contiene alguna de las prácticas no recomendadas explicadas a continuación:

  • Dependencias bloqueadas por versión: Airflow no es adecuado si necesitas dependencias o bibliotecas personalizadas. Todos los DAGs en Airflow comparten bibliotecas comunes. Todos deben adherirse a las versiones de esas dependencias. Es difícil aislar las dependencias entre diferentes DAGs.
  • Tareas intensivas en recursos: Airflow tiene un número fijo de trabajadores que ejecutan múltiples tareas en cualquier momento. Las tareas generalmente transfieren la computación a sistemas externos como Trino, pero los operadores de Python o Bash se ejecutan localmente. Las tareas intensivas en recursos pueden abrumar los nodos de los trabajadores y desestabilizar Airflow.
  • Flujos de datos con tareas dinámicas: Airflow no es adecuado para flujos de datos dinámicos que cambian la estructura del DAG en tiempo de ejecución utilizando las entradas o salidas de pasos de procesamiento anteriores.
  • Flujos de datos de alta frecuencia: Airflow está diseñado para flujos de trabajo periódicos orientados a lotes. Se deben evitar frecuencias inferiores a varios minutos.

Cuándo usar Flyte

Flyte es una buena herramienta para tareas que requieren muchos recursos y necesitan dependencias personalizadas, entornos aislados e infraestructura específica.

Reconsidera el uso de Flyte si tu flujo de trabajo contiene alguno de los antipatrones explicados a continuación:

  • Pequeños lotes: Flyte crea infraestructura desde cero y la termina después de completar la tarea. Se necesita tiempo para lanzar nuevos pods, lo cual agrega gastos adicionales cuando queremos ejecutar pequeños lotes con frecuencia. Utiliza un clúster estático en lugar de uno efímero para tareas pequeñas. Otra opción sería utilizar una arquitectura orientada a servicios y eventos. Si aún deseas utilizar Flyte, considera usar el almacenamiento en caché si es posible.
  • La detección de tablas se considera un antipatrón en Flyte. En lugar de realizar sondeos a una fuente de datos, utiliza un enfoque basado en eventos y comienza los flujos de trabajo de Flyte llamando a la API.
  • Cálculos paralelos complejos: Flyte proporciona tareas de mapeo y flujos de trabajo dinámicos, pero no es adecuado para cálculos paralelos complejos que requieren reordenamiento. Utiliza un motor de cómputo como Spark si necesitas particionamiento de datos, uniones distribuidas o agregación compleja.

Casos de uso de ejemplo

Hemos identificado dos casos de uso principales en Lyft:

  • ETL, principalmente SQL: la mayoría de estos flujos de trabajo orquestan consultas a Hive o Trino y manipulan datos en tablas SQL utilizando declaraciones SQL. Puede haber una pequeña parte de tareas no relacionadas con SQL, como la ejecución de scripts Python/Bash para exportar o importar resultados en formato CSV desde o hacia S3, o cargar resultados en una base de datos relacional. Por lo general, utilizamos Apache Airflow para este tipo de casos de uso.
  • Tareas de cómputo que requieren entornos o bibliotecas personalizadas: tareas de Python, ejecuciones de Spark con bibliotecas personalizadas (por ejemplo, frameworks para el procesamiento de datos espaciales), procesamiento de imágenes/mapas, entrenamiento de modelos de aprendizaje automático, etc. Por lo general, es mejor utilizar Flyte.

A continuación, hemos recopilado un resumen y varios casos de uso que te brindan ejemplos para distinguir entre los dos motores.

Optimización de precios para maximizar viajes y ganancias

La fijación de precios es una herramienta increíblemente poderosa para lograr los objetivos estratégicos de la empresa, ya sean ganancias, crecimiento de usuarios, frecuencia de uso, aumento de la densidad, o una combinación de todos estos factores. Debido a los millones de decisiones de precios que Lyft debe tomar al día, recurrimos al aprendizaje automático para una gran parte de nuestro sistema de precios. Una entrada importante para la fijación de precios es predecir el costo de brindar un viaje. Esto se realiza mediante un conjunto de modelos XGboost. El flujo de extremo a extremo consta de tres partes principales: preparación de datos de entrenamiento, entrenamiento del modelo y servicio del modelo.

La preparación de datos de entrenamiento es un conjunto de ETL que toma eventos como viajes, tarifas, impuestos, peajes, etc., como entrada, realiza un conjunto de consultas en Hive/Trino y produce un conjunto de datos de inferencia con características del modelo. Los ETL se ejecutan diariamente. Utilizamos Airflow porque es una excelente herramienta para alimentar ETL que orquestan sistemas externos como Hive/Trino.

El paso de entrenamiento del modelo es un conjunto de flujos de trabajo que entrenan a los modelos y generan artefactos del modelo, como el modelo XGboost en S3. Utilizamos Flyte debido a las siguientes razones:

  • Compartimos un código Python personalizado entre los flujos de trabajo, utilizando y construyendo numerosas bibliotecas. También necesitamos imágenes de Docker personalizadas.
  • Construimos tareas determinísticas y aprovechamos mucho el almacenamiento en caché: esto nos hace eficientes y reduce el tiempo de ejecución de varias horas a menos de una hora. Algunos flujos de trabajo pueden tener 20–30 tareas. Una vez que una tarea falla, podemos solucionar el problema y volver a ejecutar todo el flujo: las tareas en caché se aprobarán rápidamente. El almacenamiento en caché también nos ayuda a reducir los costos considerablemente.
  • El entrenamiento del modelo es más un proceso ad hoc que programado. Un día podemos volver a entrenar 20 modelos, y otros días no entrenamos nada nuevo. Flyte facilita llamar a flujos de trabajo con diferentes parámetros.
  • La capacidad de utilizar entornos separados: desarrollo, staging y producción, reduce errores que pueden tener un impacto significativo en Lyft si se detectan en producción.

Hacer esto para un gran número de usuarios de ETL en una versión centralizada de Airflow sería una pesadilla y nos retrasaría considerablemente.

Predicción del tiempo de llegada

El objetivo es predecir el tiempo de viaje desde el punto A hasta el punto B y mostrarlo cuando el usuario solicite un viaje. El servicio de ETA (Estimated Time of Arrival, tiempo estimado de llegada) se basa en modelos GeoBoost para proporcionar una estimación precisa.

Para la preparación de los datos de entrenamiento, tenemos ETL que agregan información sobre viajes históricos y tiempos de llegada estimados mediante un conjunto de consultas en Hive/Trino. Al igual que en el caso de uso anterior, utilizamos Airflow para este propósito.

Antes de comenzar el entrenamiento del modelo, realizamos la puntuación de los datos de los viajes. Utilizamos un componente de enrutamiento que calcula las rutas en función de la información sobre carreteras y velocidad. Un flujo de trabajo de Flyte ejecuta un motor de enrutamiento empaquetado como contenedor Docker en los viajes históricos y realiza la puntuación. Los resultados se utilizan como entrada para el paso de entrenamiento del modelo.

Utilizamos LyftLearn, una plataforma interna de aprendizaje automático, para el entrenamiento del modelo. Los flujos de trabajo de Flyte orquestan el entrenamiento del modelo y luego realizan la validación del modelo ejecutando predicciones del modelo contra el conjunto de datos producido por la versión anterior del modelo y comparando los resultados.

Provisión de señales de mercado para el cálculo de precios

El equilibrio eficiente entre la oferta y la demanda es crucial para cualquier empresa de viajes compartidos. En Lyft realizamos pronósticos en tiempo real de la oferta y la demanda. Por ejemplo, predecimos cuántos conductores estarán disponibles o cuántos viajes se solicitarán en una determinada área. Los datos de pronóstico son utilizados por diferentes consumidores, como modelos de precios.

El sistema contiene partes de transmisión en tiempo real y partes sin conexión. Los modelos consumen un flujo de eventos como viajes y telemetría de conductores y pasajeros, y predicen la oferta y la demanda, proporcionando un flujo de pronósticos. Los datos de entrada y salida se almacenan para el posterior entrenamiento y evaluación del modelo. La parte sin conexión realiza el entrenamiento del modelo, la evaluación del modelo y su publicación. El producto de la parte sin conexión es el modelo en vivo, que se ejecuta en el proceso de transmisión en tiempo real. También realizamos una evaluación regular de la salud de los modelos y generamos métricas e informes.

Utilizamos Flyte porque proporciona aislamiento del entorno y de la infraestructura, así como la capacidad de registrar flujos de trabajo a través de la API y del versionado de dichos flujos.

La versión es esencial, ya que puede haber casos en los que podamos mejorar el rendimiento del modelo, pero esto puede no traducirse en una mejora similar o equitativa en las métricas comerciales para los consumidores. De hecho, podría haber varias versiones del modelo en tiempo real en producción que se ejecutan simultáneamente, y los consumidores pueden suscribirse a los eventos producidos por una versión específica. Esto permite la interoperabilidad entre equipos, ya que los consumidores pueden permanecer en la versión anterior y realizar pruebas A-B. Cada versión del modelo está asociada con una versión del flujo de trabajo de Flyte y se etiqueta con un SHA de confirmación de Git.

Flyte proporciona una API que permite crear flujos de trabajo de forma programática. Nos permite construir dinámicamente un ecosistema complejo de flujos de trabajo sin conexión de soporte para modelos sin que el desarrollador del modelo tenga que pensarlo. Hemos creado una herramienta de gestión de flujos de trabajo que nos permite crear automáticamente flujos de trabajo de Flyte una vez que introducimos una nueva versión del modelo.

Manutención de datos del mapa precisos y actualizados mediante visión por computadora y GPU

Realizamos procesamiento de imágenes para reconocer objetos en la carretera, como señales de tráfico y conos. Luego, utilizamos la información sobre los objetos identificados para enriquecer el conocimiento del mapa, por ejemplo, determinar cierres de carreteras. Los datos del mapa más precisos nos permiten realizar un cálculo de ruta más óptimo, una estimación de ETA y costos de viaje mejorados.

El proceso implica recopilar metadatos de imágenes y utilizar modelos de aprendizaje automático de visión por computadora en PyTorch. La ejecución del modelo requiere cálculos intensivos en recursos de GPU. Flyte se utiliza para todo el flujo de trabajo, ya que nos permite aprovechar las capacidades de Kubernetes para enrutar tareas a servidores GPU cuando las necesitamos. También es necesario personalizar el clúster de Spark con bibliotecas para el procesamiento de datos espaciales, como Apache Sedona, que incluimos en una imagen de Docker compatible con el operador Spark de Flyte.

Conclusión

En este artículo, hemos compartido cómo utilizamos Airflow y Flyte para orquestar flujos de datos. Hemos cubierto varios aspectos del tema:

  • Los conceptos y la arquitectura de Airflow y Flyte en Lyft, sus ventajas y desventajas.
  • Las limitaciones de Airflow que llevaron a la creación de Flyte.
  • Recomendaciones sobre cómo elegir una herramienta en función de sus casos de usos.
  • Varios ejemplos de casos de uso que ilustran el uso de Flyte y Airflow.

Airflow es más adecuado para ETL, donde orquestamos cálculos realizados en sistemas externos. Por lo tanto, no hay necesidad de aislar los recursos de cómputo en el lado de Airflow. Además, estamos utilizando un conjunto estandarizado de bibliotecas como el cliente de Hive/Trino, por lo que no se requiere personalización de bibliotecas. Una gran ventaja de Airflow es que es fácil de aprender y brinda soporte para tareas de detección de tablas. Muchos equipos utilizan Airflow porque es rápido de implementar y no es necesario mantener imágenes de Docker o bibliotecas personalizadas.

Si la personalización del entorno y el aislamiento de recursos son una preocupación, entonces Flyte puede ser una mejor solución. Flyte se basa en Kubernetes, que proporciona estas capacidades de forma nativa. Los casos de uso típicos de Flyte son trabajos en Python o Spark que requieren bibliotecas personalizadas o marcos de aprendizaje automático. Una ventaja sustancial de Flyte es el versionado de los flujos de trabajo. Vale la pena mencionar que la personalización y el aislamiento tienen un costo: los equipos deben mantener sus imágenes de Docker. La infraestructura efímera conlleva costos adicionales excesivos para tareas de corta duración.

Elige la herramienta adecuada en función de tus requisitos y las especificaciones de tu caso de uso. Ten en cuenta que siempre habrá casos que se puedan implementar de manera suficientemente buena en cualquiera de los dos motores. Hay clases de casos de uso, como el streaming, donde ni Flyte ni Airflow son adecuados.

¿Quieres aprender más? ¡Lyft está contratando! ¡Únete a nosotros!

Reconocimientos

Un agradecimiento especial a las siguientes personas que proporcionaron comentarios, ideas, contribuyeron con sus casos de uso y ayudaron a crear este artículo: Aaron TaylorMays, Anand Swaminathan, Anmol Khurana, Artsem Semianenka, Arup Malakar, Bhuwan Chopra, Bill Graham, Eli Schachar, Igor Valko, Ilya Zverev, Jack Zhou, Ketan Umare, Lev Dragunov, Matthew Smith, Max Payton, Michael Burisch, Michael Sun, Nicolas Flacco, Niels Bantilan, Paul Dittamo, Robert Everson, Ruslan Stanevich, Samhita Alla, Sandra Youssef, Santosh Kumar, Willi Richert.

--

--