3 puntos por GN⁺ 2023-12-08 | 1 comentarios | Compartir por WhatsApp
  • FLAME busca un escalado elástico granular envolviendo partes del código de una aplicación existente como funciones para ejecutarlas en copias temporales de la aplicación, sin mover el código a un runtime separado
  • El enfoque tradicional de FaaS puede terminar creando una estructura con HTTP, S3, SQS, API Gateway, codificadores/decodificadores y orquestación de flujos de trabajo, incluso para tareas como generar miniaturas de video
  • La librería flame de Elixir delega la ejecución de funciones a un runner remoto con FLAME.call, y FLAME.FlyBackend de Fly.io arranca una nueva Fly Machine con la misma imagen Docker y la conecta al nodo padre en unos 3 segundos
  • En desarrollo y pruebas, usa LocalBackend para ejecutar en el mismo runtime, y en producción ajusta scale-to-zero y períodos cortos en estado hot con min, max, max_concurrency e idle_shutdown_after
  • En lugar de eliminar las colas de trabajo, FLAME separa la garantía de durabilidad de la ejecución elástica: la cola se encarga de dispatch, commit y retry, y el trabajo intensivo de CPU se procesa dentro de una llamada a FLAME

El problema al que apunta el patrón FLAME

  • El autoescalado elástico reduce la carga de administrar servidores y promete costos basados en uso, pero usar FaaS también puede aumentar la complejidad con colas separadas, almacenamiento, glue code y más dificultad en desarrollo, pruebas y CI
  • FLAME significa Fleeting Lambda Application for Modular Execution y trata a toda la aplicación como si fuera una lambda, ejecutando solo algunos trabajos modulares en infraestructura efímera
  • El objetivo se resume en tres puntos
    • Reducir la administración de servidores usando flujos de despliegue existentes como fly deploy, git push heroku y kubectl
    • Escalar de forma granular y bajo demanda solo partes específicas del código de la aplicación
    • No reescribir la aplicación ni mover parte del código a un runtime propietario

Mover funciones existentes con FLAME.call

  • El ejemplo es la función generate_thumbnails, que convierte videos subidos en miniaturas con ffmpeg dentro de una aplicación Elixir
  • La función original crea un directorio temporal, ejecuta ffmpeg, guarda las miniaturas generadas en almacenamiento duradero y registra las URL en la base de datos con Repo.insert_all
  • Como la transcodificación de video intensiva en CPU puede detener todo el servicio en producción, en vez de mover todo el código a FaaS o a un microservicio, se envuelve el cuerpo de la función en FLAME.call(MyApp.FFMpegRunner, fn -> ... end)
  • FLAME.call recibe el nombre del pool de runners y una función, luego encuentra o arranca una nueva copia completa de la aplicación y ejecuta solo esa función
    • Variables capturadas por el closure, como la estructura %Video{} y interval, se transfieren automáticamente
    • El runner de FLAME se conecta al nodo padre tras arrancar, recibe la función a ejecutar y devuelve el resultado al llamador
    • Según la configuración, el runner espera más trabajo y luego baja al quedar idle, o termina de inmediato
  • Como se ejecuta toda la aplicación, incluida la conexión a la base de datos, se puede seguir usando Repo.insert_all tal como estaba

Complejidad de FaaS y diferencia con FLAME

  • FaaS ofrece componentes para resolver el problema, mientras que FLAME se acerca más a reducir la propia capa de comunicación separada
  • En el ejemplo de miniaturas de video, incluso si se empieza con un simple AWS Lambda Function URL, pronto aparece la complejidad
    • Para volver a transmitir por HTTP las miniaturas a la app, hay que escribir codificadores y decodificadores personalizados en ambos lados
    • Si la transcodificación o la subida del video supera 15 minutos, el hard timeout de Lambda obliga a dividir el video en chunks y usar más Lambdas
    • Se necesitan más servicios como orquestación de workflows y componentes adicionales como SQS y S3
  • Una implementación basada en FaaS normalmente crea estos puntos de costo
    • Disparar la Lambda con un endpoint HTTP, S3 o API Gateway
    • Escribir una Lambda personalizada para la transcodificación de video
    • Guardar los resultados de las miniaturas en SQS
    • Escribir un consumer de SQS del lado de la app
    • Guardar en la base de datos y armar una forma de reenviar eventos a suscriptores activos conectados a otras instancias
  • FLAME permite seguir usando el código interno de la aplicación, la base de datos existente, PubSub y las funciones de la plataforma, reduciendo servicios externos y almacenamiento intermedio para recuperar resultados

Backend de Fly.io y ejecución local

  • La librería flame de Elixir implementa el patrón FLAME y ofrece por defecto LocalBackend y FlyBackend
  • FLAME.FlyBackend arranca una nueva copia de la aplicación en una Machine de Fly.io y puede conectarla al nodo padre para recibir trabajo en unos 3 segundos
  • Como Fly.io ejecuta aplicaciones empaquetadas como imágenes Docker, se le pide a la API de Fly que arranque una nueva Machine con la misma imagen que la app actual
  • En la infraestructura de Fly.io, los runners de FLAME pueden iniciarse en la misma región que el padre, reduciendo la latencia entre ambos
  • FLAME.FlyBackend tiene menos de 200 LOC, incluida la documentación, y su única dependencia de librería es el cliente HTTP req
  • En desarrollo y pruebas, LocalBackend ejecuta ese código dentro del runtime existente de la laptop o del servidor de CI

Transferencia de archivos y simplificación de desarrollo y pruebas

  • FLAME reutiliza la lógica de negocio, la configuración de base de datos, PubSub y las funciones de la plataforma sin escribir código fuera de la aplicación
  • En Elixir, gracias a las funciones distribuidas de la VM de Erlang, se puede enviar el stream de un archivo desde el nodo padre a la aplicación FLAME remota
    • En el nodo padre, se abre el stream del archivo de la ruta del video
    • En el hijo FLAME, se abre un stream de archivo temporal y se copia el stream del padre
    • Después, ffmpeg usa el archivo temporal del runner remoto como entrada para generar miniaturas
  • Con este enfoque, se puede pasar el archivo al servidor FLAME sin tener que configurar aparte interfaces S3 o HTTP
  • También se reduce la necesidad de desplegar servicios separados, administrar endpoints, recuperar resultados por S3/SQS y configurar dependencias para desarrollo, pruebas y CI

FLAME fuera de Elixir

  • Elixir encaja bien con el modelo FLAME por ofrecer supervisión de procesos y mensajería distribuida, pero otros lenguajes con primitivas razonables de concurrencia también pueden usar este patrón
  • Hay una prueba de concepto en JavaScript que ejecuta funciones de una aplicación en otra máquina Fly Machine: fly-run-this-function-on-another-machine
  • El flujo general de una llamada tipo FLAME en JavaScript consiste en mover la parte que ejecuta el módulo a un archivo nuevo y correrla en un pool de runners
  • Si los argumentos son serializables a JSON, el flujo completo se parece al ejemplo de Elixir: el código de la aplicación se ejecuta en una instancia efímera
  • Una librería FLAME completa tendría que encargarse de lo siguiente
    • Lógica de scale-up y scale-down de pools elásticos
    • Gestión del pool considerando hot startup y cold startup
    • Monitoreo de runners remotos para evitar recursos huérfanos
    • Mecanismos para mantener los despliegues actualizados

Relación con las colas de trabajos en segundo plano

  • FLAME también funciona dentro de procesadores de trabajos en segundo plano, pero hay cierta superposición de funciones con las colas de trabajo
  • Las colas de trabajo suelen usarse cuando se necesita garantía de durabilidad, y pueden ajustarse para procesar más trabajos según cambie la carga
  • El trabajo duradero y la ejecución elástica son preocupaciones separadas
    • Si la cola se usa solo para offload de ejecución, hace falta glue code para meter los datos del trabajo y devolver los resultados al llamador o al dispositivo del usuario
    • Si se necesita garantizar que la generación de miniaturas tras subir un video tenga éxito, la cola puede encargarse de dispatch, commit y retry
    • La transcodificación real puede ejecutarse con una llamada a FLAME dentro del trabajo, separando durabilidad y ejecución escalable
  • Tareas que no necesitan durabilidad, como una vista previa de video antes de guardar o ejecutar un modelo de ML cuando el usuario ya salió de la app, pueden no encajar con una arquitectura que escribe trabajos en almacenamiento duradero

Pools de runners para escalado elástico

  • La implementación de FLAME en Elixir define un pool elástico de runners que soporta tanto scale-to-zero como límites de concurrencia
  • El ejemplo de configuración agrega FLAME.Pool al start/2 de la aplicación
    • min: 0 permite scale-to-zero
    • max: 10 arranca hasta 10 runners como máximo
    • max_concurrency: 5 soporta 5 trabajos de ffmpeg por runner
    • idle_shutdown_after: 30_000 hace idle down si no hay llamadas durante 30 segundos
  • El servidor web de Phoenix se inicia de forma condicional según exista o no el padre de FLAME
    • En runners FLAME que no manejan tráfico web, no hace falta iniciar el servidor web
    • MyApp.Repo y componentes similares se dejan activos porque deben usarse dentro del runner FLAME
  • Si se define min: 1, se puede mantener al menos un runner de ffmpeg en estado hot desde el arranque de la aplicación

Ubicación de procesos con estado

  • Las partes con estado de una aplicación Elixir suelen construirse alrededor de primitivas de procesos livianos con mailbox de mensajes
  • FLAME.call y FLAME.cast son adecuados para código relativamente stateless, mientras que FLAME.place_child arranca una especificación de proceso existente en un runner FLAME en vez de hacerlo localmente
  • FLAME.place_child puede usarse en lugares donde normalmente se usarían interfaces como Task.Supervisor.start_child o DynamicSupervisor.start_child
  • En el ejemplo de generar miniaturas durante una subida con LiveView, los chunks del upload se envían a un proceso ThumbnailGenerator, que se comunica con ffmpeg
    • Cuando encuentra un delimitador PNG en stdout de ffmpeg, envía un mensaje con la imagen al proceso de LiveView
    • LiveView recibe el mensaje en handle_info y agrega la nueva imagen a la UI
  • Si se cambia una llamada existente como DynamicSupervisor.start_child(@sup, spec) por FLAME.place_child(Thumbs.FFMpegRunner, spec), el proceso ThumbnailGenerator pasa a ejecutarse en un runner FLAME
  • Como los procesos pueden enviarse mensajes sin importar dónde estén, si el proceso termina porque concluyó la subida o se cerró la pestaña del navegador, el servidor FLAME detecta la finalización y baja al quedar idle si no hay más trabajo

Monitoreo remoto y manejo de fallos

  • La infraestructura efímera necesita mecanismos de seguridad para evitar recursos huérfanos
  • Cuando el padre levanta un runner, este debe apagarse solo al quedar idle y también ejecutar un failsafe shutdown si ya no puede comunicarse con el nodo padre
  • Si un nuevo despliegue reemplaza al padre, los runners también deben apagarse para garantizar que el clúster ejecute el mismo código
  • Los llamadores activos que esperan resultados de un runner deben considerar que el runner puede caer por cualquier motivo
  • Las primitivas que ofrece la VM de Erlang simplifican esta implementación
    • Monitoreo y supervisión de procesos locales y remotos
    • Node monitoring para detectar cuándo un nodo sube o baja
    • Flujos de shutdown que controlan el orden de inicio y cierre de aplicaciones, dando tiempo a que runners activos terminen su trabajo durante un nuevo despliegue
  • Los detalles internos de implementación seguirán en otro artículo; por ahora se puede revisar el código fuente de flame

Estado actual y siguientes pasos

  • La librería FLAME de Elixir todavía está en una etapa temprana, pero ya se puede probar
  • Más adelante se planean técnicas más avanzadas de crecimiento del pool y un análisis en profundidad de cómo se implementa en Elixir
  • También se puede discutir cómo implementar el patrón FLAME en otros lenguajes

1 comentarios

 
GN⁺ 2023-12-08
Comentarios de Hacker News
  • Después de haber sufrido el dolor y la complejidad de una app con más de 100 funciones Lambda durante los últimos 4 años, creo que este artículo apunta exactamente a las desventajas de la arquitectura serverless FaaS
    Cuando uno empieza, estas desventajas no se notan mucho. Más bien, si el uso es bajo, sobresalen claramente las ventajas de que sea casi gratis y requiera casi nada de mantenimiento
    Más adelante, cuando los flujos de trabajo de Lambda se enredan y se vuelven cada vez más rígidos por las interdependencias, uno termina arrepintiéndose y pensando que habría sido mejor ir por un monolito y autoadministrarlo pagando unos cientos de dólares más. Hoy en día, con algo como fly.io, incluso podría costar menos
    Me pregunto cómo sería esto si no usas Elixir

    • He seguido viendo el mismo patrón: desarrolladores con iniciativa pueden hacer que casi cualquier proceso o arquitectura funcione durante unos 18 meses, y ya parece casi una ley o una regularidad
      Para cuando la situación se pone fea, también suele ser el momento de buscar otro trabajo. Sobre todo si, después de alrededor de un año en la empresa, ya te arrepientes del proceso que tú mismo introdujiste. Lo he visto muchas veces con malos jefes, ‘pruebas unitarias’ desastrosas, Scrum y demás
      Aun así, no sé si la gente identifica con claridad la causa de la incomodidad que siente en el trabajo, o si simplemente lo interpreta como “ya es hora de irme”. Cuando he intentado ponerle nombre a lo incómodo, he recibido mucha resistencia, y después de leer Good to Great, eso me desgasta mucho menos. Nadie quiere decir “ah, son las consecuencias de mis actos”
      Las personas que realmente construyeron los sistemas tipo Rube Goldberg que ahora me toca mantener fueron las primeras en irse. El capitán de ese barco le preguntó a un colega qué le parecía open source nuestro motor, y el colega respondió que nadie querría usar un sistema que reinventa una rueda que ya existe y además es mejor. Esa persona se fue por voluntad propia en 3 o 4 meses
    • Estamos construyendo algo que podría resolver este problema en cualquier lenguaje. Por ahora tenemos un SDK de TypeScript y también estamos trabajando en Java
      Si se pudiera escribir código orientado a servicios normal donde las Lambdas se llamen entre sí, no haría falta dividir la aplicación en cientos de fragmentos de ejecución corta. Pero si tienes que pagar incluso por el tiempo de espera, eso no es viable. Si Lambda pudiera pausar la ejecución mientras espera E/S, el problema se resolvería. Por eso creo que la ejecución durable (durable execution) puede ser la respuesta
      En las últimas semanas estuve escribiendo un artículo para mostrar esto: https://restate.dev/blog/suspendable-functions-make-lambda-t...
    • En una sección del artículo también hablé de FLAME fuera de Elixir. En resumen, es un patrón generalmente aplicable en lenguajes con un modelo de concurrencia razonable
      Tal vez no se pueda obtener toda la usabilidad que en Elixir viene gratis, como funciones con serialización de variables capturadas, pero en lenguajes como JavaScript parece que se podría llegar al 90% moviendo el cuerpo ejecutable del módulo a otro archivo, en vez de envolverlo en un closure
      Quien implemente la librería FLAME también tendrá que escribir la parte de pooling, monitoreo y comunicación remota. Elixir ofrece gratis muchas cosas del lado de la mensajería distribuida y el monitoreo. Las funciones relacionadas con la ubicación de procesos, en la práctica, también son algo casi exclusivo de Elixir
    • Incluso con solo 12 Lambdas ya era difícil de soportar. La app original la hizo alguien que no había pensado mucho en mantenimiento ni despliegue, y había copiar y pegar de código por todos lados
      Al final migramos a un Lambda monolítico y gordo donde una sola Lambda maneja varios endpoints
    • Si no te preocupan demasiado los cold starts o puedes manejarlos, también puedes hacer un monolito en Lambda
      Dicho de otro modo, puedes ir por un monolito y aun así minimizar el costo en AWS. No es un caso donde haya que elegir solo una de las dos cosas
      Últimamente uso asp.net, y hasta apps bastante grandes desplegadas como ready-to-run, incluyendo modelos de EF optimizados, arrancan relativamente rápido
  • Soy el autor. Me alegra por fin poder publicarlo y responderé preguntas si las hay. Espero que esto motive lo suficiente a algunas personas para implementar el patrón FLAME en JavaScript, Go y otros lenguajes

    • Se ve bien. Ojalá Microsoft le prestara atención. Azure Functions es demasiado complejo en configuración de seguridad y despliegue, y parte de suposiciones raras sobre qué tipo de código quieres ejecutar
    • La implementación más natural probablemente sería algo como vert.x en la JVM
      Ya tiene mecanismos para manejar ejecución asíncrona mediante extensiones reactivas, Future y corrutinas sobre un event bus, y también soporta serialización y distribución de datos en todo el clúster. Además, como hay clientes de event bus para varios lenguajes populares, debería ser posible construir una aplicación mezclando varios lenguajes
    • Conviene bajar un poco la exageración
      Si presentas el problema como una “…condena peor que la muerte” y la solución como algo tan fácil e indoloro que cualquiera que no abandone otros enfoques parece tonto, este tipo de artículo se descarta fácilmente como simple texto de ventas. Esa es la forma de los vendedores de panaceas
      Al principio del artículo sí se planteó bien el problema, así que para quienes sienten curiosidad por un mejor enfoque, creo que una comparación objetiva mucho menos emocional habría generado menos rechazo
      El contenido sustancial del artículo me pareció interesante, pero la forma de expresarlo me echó para atrás. Espero que lo tome como retroalimentación constructiva
    • El artículo y el video están buenos, y el concepto también es muy interesante. Espero con ganas una implementación en JavaScript, aunque no parece fácil
      Y también me hizo sentir un poquito culpable haber apartado ffmpeg.fly.dev
    • Me pregunto en qué se diferencia esto, en lo fundamental, de la forma en que Sidekiq instancia una base de código de Rails para ejecutar trabajos en segundo plano
  • La parte de “imagina que cualquier parte del código de tu app existente se puede envolver como una función, escalar automáticamente, y que ese bloque de código se ejecuta en una copia temporal de la app” me pareció interesante
    Suena como si hubieran adaptado lo que hace fork para serverless. Excelente trabajo

  • Hace algunos años usé un servicio que básicamente hacía esto. PiCloud lamentablemente fue absorbido por Dropbox, pero antes tenía exactamente este modelo, donde distribuía transparentemente el trabajo entre workers. Funcionaba empaquetando el código y ejecutándolo en el worker.
    Aquí hay un ejemplo. Se puede ver que es exactamente el mismo modelo: https://github.com/picloud/basic-examples/blob/master/exampl...
    Nunca he usado Elixir, pero sí usé Erlang hace décadas, y BEAM no parece haber cambiado mucho en lo fundamental. Como eso forma parte del núcleo del diseño, parecería mucho más adecuado para este tipo de trabajo. Aun así, no creo que sea un almuerzo gratis completo, porque supongo que el proceso principal podría morir mientras espera

  • Estoy de acuerdo con el argumento general. En https://www.windmill.dev tomamos otro enfoque: consideramos que la unidad de abstracción no está al nivel del contenedor, sino al nivel del código fuente.
    Parseamos la función main y los imports para extraer parámetros y dependencias, y luego ejecutamos el código tal cual en el runtime que quieras (TypeScript, Python, Go, Bash). El truco principal es administrar el caché de forma eficiente para que los workers siempre permanezcan calientes, independientemente de los imports.
    Este enfoque no se integra tanto con la base de código como FLAME, pero apunta a un usuario diferente. Nuestros usuarios crean desde cero workflows complejos, tareas cron o scripts de una sola vez con UI autogenerada.
    En FLAME, parece que se toma un snapshot de todo el contexto y luego se restaura en la VM de destino. Otro enfoque es introducir una sintaxis para especificar qué contexto se necesita y cuál no, para cargar solo lo mínimo. Lo estamos explorando actualmente para integrar mejor las bases de código existentes con Windmill y no depender de llamadas HTTP.

    • En realidad, eso no es exactamente lo que pasa en FLAME. FLAME simplemente invoca una función en un nodo remoto usando la funcionalidad de clustering incorporada de BEAM.
      En ese proceso, solo se transmite implícitamente el contexto necesario. El artículo lo explica así: “FLAME.call recibe el nombre del pool de runners y una función. Luego busca o arranca una nueva copia de toda la aplicación, y ejecuta la función allí. Las variables capturadas por cierre en la función, por ejemplo la estructura %Video{} y interval, también se transfieren automáticamente”
    • Hay una w extra. Para quienes lo estén buscando, la URL es esta: https://www.windmill.dev/
      Me gusta el objetivo del proyecto. De verdad espero que Windmill se convierta en una mejor alternativa open source a Retool/Airtable
  • Me gusta que “en FLAME los runners de desarrollo y prueba simplemente se ejecutan en el backend local”. Qué bueno un serverless con una experiencia de desarrollo local decente.

    • Exacto. Una de las razones por las que no me gusta serverless es que la experiencia de desarrollo local es mucho peor que simplemente ejecutar un monolito
  • Si “luego busca o arranca una nueva copia de toda la aplicación y esa función se ejecuta allí”, entonces ¿cada Flame.call inicia de nuevo todo el proceso de la app y copia dentro el contexto de ejecución?
    Desde el punto de vista de la escalabilidad, parece una solución muy simple, pero imagino que también tendrá desventajas.
    Si el tiempo de arranque de la app aumenta 10 ms, eso significa 10 ms extra en todos los puntos de Flame.call de la aplicación, y con la memoria parecería pasar algo parecido.
    Supongo que al usar este sistema hay que tener en cuenta esas preocupaciones.

    • La sección de FLAME.Pool más adelante en el artículo cubre justo eso. Los runners se agrupan en pools y se mantienen calientes durante un tiempo configurable antes de bajar a estado inactivo.
      Cuando hay carga, el pool ya está caliente, así que casi no pagas costo de cold start. Además, estamos agregando a la librería de Elixir una técnica más sofisticada para aumentar el pool, para evitar también la situación en la que te topas con un runner lleno y tienes que hacer otro cold start.
      En un runner caliente, el único overhead es la latencia entre padre e hijo. Como tienen que estar en el mismo datacenter, será de 1 ms o menos
  • Excelente. Se siente como una versión solo para Elixir y mucho más ligera de lo que construimos en https://www.inngest.com/.
    Ambos se parecen en que envuelven código existente en algo que se puede usar en funciones serverless, y esencialmente permiten invocarlo mediante RPC remota.
    Este tipo de código a menudo se ejecuta como una secuencia de pasos imperativos. Cada paso puede ejecutarse en serie o en paralelo como Lambdas adicionales. Pero entre los pasos existe un estado implícito capturado en variables. Por eso la función se convierte en un workflow. En el modelo de Inngest, ese estado se captura y se vuelve a inyectar en la función para darle durabilidad.
    Desde el punto de vista de la durabilidad, este tipo de proceso debería basarse en una cola. Lo bueno de este modelo es que las colas son baratas. Si logras que una cola sea tan barata como una línea de código, todo se vuelve más fácil. Cualquier desarrollador puede escribir código confiable sin preocuparse por la infraestructura.
    El monitoreo y la observabilidad también son importantes. Las dead-letter queues son realmente horribles, y necesitas poder administrar y volver a ejecutar funciones o pasos que fallen.
    También hay diferencias entre FLAME e Inngest. Inngest está basado en colas, es impulsado por eventos y puede exponerse por HTTP desde cualquier lenguaje. Como Inngest guarda el estado externamente, puedes escribir un workflow en Elixir, reescribirlo en TypeScript y volver a desplegarlo, y las funciones en ejecución pueden migrarse en vivo entre lenguajes backend, de forma parecida a CRIU.
    Al ser un enfoque impulsado por eventos, también permite control de flujo. Debounce, batching, throttling y fanout pueden manejarse en cualquier runtime o lenguaje. Por ejemplo, una app de Elixir en Fly puede emitir un evento para ejecutar una función en TypeScript + Lambda.
    Tengo curiosidad por ver hacia dónde va FLAME. Creo que hay partes del objetivo que son similares.

    • Inngest parece un servicio genial. El artículo también habla de job handlers, durabilidad y reintentos.
      Cuando se necesita durabilidad, reintentos y workflows en Elixir, normalmente se usa Oban, y aquí también seguiríamos haciéndolo. Un job de Oban sería el que invoque FLAME para encargarse de la ejecución elástica
  • Esta es una de las razones por las que de verdad odio la capitalización estilo estadounidense de los títulos que impone HN. Serverless parece significar “replantear Serverless”, la empresa con S mayúscula de serverless.com, y no “replantear serverless” como principio con s minúscula
    Dicho eso, ojalá alguien replanteara Serverless

    • Creo que la capitalización no la impone HN, sino quien publica el post
      No sé si viste https://sst.dev/, pero parece que ellos hicieron exactamente eso. Por ejemplo, tienen Live Lambda Development, así que el desarrollo local se vuelve realmente fácil al reducir muchísimo el ciclo de retroalimentación, sin tener que subir el código a la nube y esperar el despliegue
  • La idea está bastante buena y la API es excelente
    La parte de “las tareas CPU-bound como la transcodificación de video pueden detener rápidamente todo el servicio en producción” me hace pensar: ¿no bastaría con hacer autoescalado según CPU?

    • Quise abordar esa idea al principio del artículo. El problema con ese enfoque es que escala en el nivel equivocado de operación
      Terminas escalando toda la aplicación, incluido el servidor web, para manejar una tarea puntual que se calentó. Lo que queremos, y por lo que uno termina buscando FaaS, es un escalado elástico granular. La idea aquí es permitir ese tipo de escalado fino sobre el código existente de la app, en vez de solo aplastar los botones de escalar webservers o workers y esperar que salga bien
    • Sí y no. Puede que el resto de la carga de trabajo no necesite mucho CPU. Tal vez solo una o dos cargas requieran este nivel de rendimiento, y quieras asegurarte de que esa tarea no quede desplazada por otras
      O quizá necesites una GPU
      El servicio principal puede funcionar bien con 1 o 2 servidores, pero para una tarea que ocurre quizá una vez al día podrías necesitar escalar a decenas, cientos o miles de máquinas cuando haga falta