Funciones, contenedores gestionados o Kubernetes, decidido por cinco variables

La elección no va de elegancia. Va de la forma del tráfico, la tolerancia al arranque en frío, la duración de la ejecución, el control del entorno y lo que tu equipo puede operar de verdad a las tres de la madrugada.

La discusión ocurre normalmente al nivel de abstracción equivocado. Alguien dice que serverless no escala, otro dice que Kubernetes es sobreingeniería, y los dos están describiendo cargas que han ejecutado y no la que tienen delante.

Hay cinco variables que deciden esto de verdad, y para la mayoría de los servicios tres de ellas apuntan en la misma dirección.

Forma del tráfico y tiempo ocioso

La variable más importante, y la que vuelve obvia la aritmética de coste en cuanto la has medido.

Las funciones facturan por invocación y por unidad de tiempo de ejecución. Con tráfico cero no pagas nada. Eso es decisivo para todo lo irregular, ocasional o impredecible: un receptor de webhooks, un trabajo programado, una herramienta interna que se usa cuarenta veces al día, una funcionalidad que nadie ha adoptado todavía.

Los contenedores sobre infraestructura siempre encendida facturan por tiempo llame alguien o no. Eso es decisivo en la otra dirección: un servicio con tráfico constante durante la jornada sale mucho más barato por petición en un contenedor que ya pagas que con precio por invocación.

El punto de cruce no está donde la gente supone. Mide peticiones por segundo en la mediana y en el pico, y la duración de cada una. Un servicio con tráfico sostenido apreciable suele salir más barato en contenedores; cualquier cosa con una cola larga de inactividad suele salir más barata en funciones. Las plataformas gestionadas de contenedores que escalan a cero se sitúan entre ambas y son la razón de que exista la opción intermedia.

Tolerancia al arranque en frío

Una función que no se ha ejecutado hace poco tiene que inicializarse antes de poder servir. Cuánto importa eso depende enteramente de quién está esperando.

Un consumidor asíncrono que procesa una cola no se entera. Un trabajo en segundo plano no se entera. Una API de cara al usuario donde una fracción de las peticiones tarda un segundo más sí se entera, y esa fracción no es pequeña con poco tráfico, porque el poco tráfico es exactamente lo que causa los arranques en frío.

Las mitigaciones son reales y cada una cuesta algo. Los ajustes de instancias mínimas o aprovisionadas mantienen instancias calientes, lo que elimina el problema y también elimina el ahorro de escalar a cero que te hizo elegir funciones. Un paquete de despliegue más pequeño y un tiempo de ejecución de arranque rápido ayudan bastante; un marco pesado con un árbol grande de dependencias es la causa habitual de un arranque lento. Los lenguajes difieren, y la diferencia es lo bastante grande como para cambiar la decisión en un servicio sensible a la latencia.

Duración y forma de la ejecución

Las funciones tienen un tiempo máximo de ejecución, y es corto para cierto trabajo real. Una transcodificación larga de vídeo, una exportación grande de datos o un trabajo por lotes que corre una hora no caben, y los rodeos, encadenar invocaciones o guardar puntos de control, son más complejos que simplemente ejecutar un contenedor.

La restricción relacionada es el modelo de ejecución. Una función atiende una petición cada vez por instancia en casi todas las plataformas, así que una carga que hace mucha espera de entrada y salida está pagando cómputo ocioso. Las plataformas gestionadas de contenedores que permiten muchas peticiones simultáneas por instancia son bastante más baratas para esa forma, y es uno de los argumentos más fuertes a favor de la opción intermedia.

Considera además qué necesita conservar la carga. Las funciones no tienen estado entre invocaciones, solo un sistema de ficheros temporal y ninguna caché local fiable. Un servicio que se beneficia de una caché caliente en memoria o de una reserva de conexiones persistente funciona mal como función y bien como contenedor.

Control del entorno

Las funciones te dan un tiempo de ejecución y un conjunto de lenguajes soportados, con empaquetado como imagen de contenedor disponible ya en casi todas las plataformas, lo que elimina buena parte de esta restricción. Las plataformas gestionadas de contenedores te dan una imagen y un tiempo de ejecución controlado. Kubernetes te lo da todo, incluidas las partes que no querías.

La pregunta que hay que hacerse es qué necesita tu carga que un entorno restringido prohíba: una librería de sistema concreta, un hilo en segundo plano, un sidecar, una GPU, una función concreta del núcleo, una conexión de larga vida con algo que no tolera reconectar.

Casi ningún servicio web necesita nada de esto, que es por lo que casi ningún servicio web debería estar en Kubernetes por razones técnicas. Algunos sí lo necesitan de verdad.

Lo que tu equipo puede operar

Esta es la variable que los equipos ponderan la última y deberían ponderar la primera.

Kubernetes es una plataforma con una guardia, una cadencia de actualizaciones y un conjunto de modos de fallo que exigen conocimiento específico, como se ve en actualizaciones de clúster y varios equipos en un clúster. Es la respuesta correcta cuando tienes suficientes servicios para amortizar ese coste, o cuando necesitas lo que solo él da.

Para un equipo de cinco personas con un producto, una plataforma gestionada de contenedores es casi siempre la mejor respuesta, y la comparación para una nube está en Cloud Run o GKE. Obtienes autoescalado incluido el escalado a cero, un modelo de despliegue, reparto de tráfico y ningún clúster.

Las funciones encajan con equipos que quieren desplegar una unidad de lógica y dejar de pensar en ella, y encajan con el pegamento dirigido por eventos mejor que ninguna otra cosa.

Los costes que no salen en la página de precios

  • Desarrollo y pruebas en local. Reproducir el entorno de una función en local es más difícil que ejecutar un contenedor, y los equipos subestiman el lastre que eso crea en cada cambio.
  • La observabilidad difiere. Trazar entre funciones exige propagar el contexto deliberadamente, y el modelo de ejecución corta lo complica, que es el problema del salto por cola de trazas con las que depuras de verdad.
  • La atadura está en los enlaces de eventos, no en el código. El manejador es portable. Los disparadores, el modelo de identidad y los servicios gestionados de alrededor no lo son. Eso suele ser aceptable y debería ser una decisión y no un descubrimiento.
  • Límites de concurrencia y cuotas. Los techos de concurrencia por cuenta son reales y se encuentran durante un pico de tráfico.
  • Presión aguas abajo. Una función que escala a mil instancias simultáneas abrirá mil conexiones a la base de datos salvo que algo lo impida. Es la caída serverless más común que vemos, y el arreglo es un proxy de conexiones o un límite de concurrencia.

La forma que suele ganar

Casi todos los entornos acaban mezclados, y eso es correcto en vez de un fallo de disciplina.

Funciones para el pegamento dirigido por eventos, los trabajos programados, los manejadores de webhooks y todo lo que tenga una cola larga de inactividad. Una plataforma gestionada de contenedores para los servicios que atienden peticiones con requisitos normales, que son casi todos. Kubernetes cuando tengas suficientes servicios, suficientes equipos o suficientes requisitos específicos para justificar ser su dueño.

Decide por carga de trabajo en vez de elegir una plataforma y forzarlo todo a ella. El coste de operar dos plataformas es real pero menor que el de operar la equivocada para la mitad de tus cargas.

Qué hacer esta semana

Coge tus tres servicios más caros y escribe dos números por cada uno: peticiones por segundo en la hora mediana, y porcentaje del día prácticamente sin tráfico. Esa tabla responde a la pregunta de plataforma para casi todos los servicios sin más análisis, y normalmente contradice al menos una decisión que alguien tomó hace dos años. La construimos en la fase de arquitectura de un proyecto cloud.

ConsultorIA

¿Quieres esto en tu nube?

El diagnóstico de diez días en solo lectura es gratuito, y con Skyline puedes ver tu entorno en un mapa antes de escribirnos.

Artículos relacionados

Módulos que la gente reutiliza en vez de copiar

Los dos fracasos son un módulo que envuelve un recurso y no aporta nada, y un módulo que lo hace todo y que nadie se atreve a cambiar. Una interfaz mínima, valores por defecto seguros y un versionado honesto son lo que los separa.