Diseñar una función Lambda aislada es sencillo. Diseñar una plataforma que despliega más de un millón de funciones Lambda repartidas en miles de cuentas de AWS, para clientes distintos, con aislamiento real entre ellos, es un problema completamente distinto. No es un problema de más código: es un problema de arquitectura organizativa, cuotas de servicio y coste operativo.
Un caso reciente documentado por el equipo de ProGlove, fabricante de escáneres inteligentes para entornos industriales, junto con Solutions Architects de AWS, describe muy bien ese recorrido: de una plataforma serverless modesta a una arquitectura una cuenta de AWS por cliente (tenant) operando a escala de millón de funciones. El viaje está lleno de decisiones que solo tienen sentido cuando el volumen te obliga a tomarlas.
Por qué una cuenta de AWS por cliente
La decisión de partida fue usar el modelo una cuenta AWS por tenant, en lugar de compartir cuentas entre clientes. La razón no es solo seguridad: es simplicidad operativa y, sobre todo, aislamiento de cuotas. Cada cuenta tiene su propio límite de concurrencia de Lambda, su propio throttle de API Gateway, sus propios service quotas. En un modelo de cuentas compartidas, un solo cliente ruidoso puede agotar la concurrencia y provocar fallos en cascada sobre el resto. Con aislamiento por cuenta, esa clase de problema deja de existir directamente.
Fase 1: los orígenes simples (0 a 1.000 funciones)
Al principio, todo cabe en la cabeza: un puñado de funciones, patrones estándar como Amazon SQS para desacoplar servicios, y scale-to-zero tratado como algo deseable pero no crítico. Cada microservicio se compone de entre 5 y 15 funciones Lambda, coordinadas por AWS Step Functions, con Amazon EventBridge gestionando el enrutado de eventos y Amazon DynamoDB como almacén de datos principal, todo empaquetado en un stack de AWS CloudFormation.
El primer cuello de botella llegó rápido: desplegar y actualizar stacks manualmente cuenta por cuenta no escala. La respuesta fue adoptar CloudFormation StackSets, que permite empujar actualizaciones de infraestructura a múltiples cuentas en paralelo desde una cuenta de gestión central. Se evaluó construir un reemplazo totalmente propio, pero se descartó: el coste de mantenimiento no compensaba la ganancia marginal de control.
Fase 2: las primeras 50 cuentas
Llegar a 50 cuentas de cliente obligó a resolver tres problemas que a escala pequeña eran invisibles: observabilidad, aprovisionamiento de cuentas y aislamiento de cuotas.
- Aprovisionamiento automatizado: se construyó un "account factory" sobre AWS Organizations, con un flujo de Step Functions en la cuenta de gestión que crea la cuenta, aplica Service Control Policies (SCPs) base, arranca roles IAM cross-account y dispara el despliegue inicial del StackSet. Todo mediante invocaciones Lambda cross-account. El resultado: una cuenta nueva lista en menos de 15 minutos.
- Aislamiento real de cuotas: cada cuenta tiene su propio límite de concurrencia Lambda y su propio throttle de API Gateway, lo que confirma en la práctica el beneficio del modelo de partida frente a un esquema de cuentas compartidas.
Fase 3: el "self-DDoS" — cuando tu propia plataforma te ataca
Pasadas las primeras cientos de cuentas, apareció lo que el equipo llamó la "física de la escala": cuando cientos de instancias de un mismo servicio backend acceden a otros servicios de forma simultánea, el volumen de peticiones puede parecerse a un ataque coordinado, tanto contra su propia infraestructura como contra la de AWS.
El caso concreto fue un pico masivo de métricas: miles de funciones Lambda usando la misma expresión
de programación rate(5 minutes), todas alineadas al mismo minuto exacto en miles de cuentas
a la vez. El resultado fue que sus propias funciones saturaron sus APIs internas.
La solución fue dispersar las peticiones: una librería interna estandarizada que añade jitter, offsets de batch aleatorios y actualizaciones escalonadas en todas las funciones programadas. La regla que se quedaron fue simple: nunca hacer lo mismo, al mismo tiempo, en todas partes.
Observabilidad multi-cuenta: de gasto insignificante a partida crítica
Con decenas de cuentas, revisar logs manualmente cuenta por cuenta dejó de ser viable. Se adoptó una plataforma de observabilidad de terceros, reenviando logs y métricas de CloudWatch de forma cross-account hacia un dashboard centralizado. A unos 3 dólares por cuenta al mes, el coste parecía irrelevante.
Esa suposición no sobrevivió a la escala: a miles de cuentas, esos 3 dólares por cuenta se convirtieron en una partida de coste que exige gestión activa. El hallazgo más sorprendente no fue el cómputo de Lambda ni el almacenamiento, sino que reenviar todos los datos de observabilidad casi duplicó la factura cloud completa. La respuesta fue aprender a diferenciar datos de observabilidad de alta y baja prioridad, y mover solo los que de verdad importaban — bajando el coste medio a unos 0,70 dólares por cuenta, y prácticamente a cero en cuentas inactivas monitorizando solo un pequeño conjunto de métricas básicas.
Repensar SQS: el dilema de las colas y el DLQ
Una de las lecciones más incómodas fue descubrir que las "buenas prácticas" habituales con Amazon SQS encarecían el sistema a esta escala concreta. Cuando una función Lambda consume eventos de EventBridge a través de una cola SQS para ganar resiliencia, hace peticiones constantes a la cola incluso sin mensajes que procesar. "Inactivo" no significa "sin coste".
- Se eliminó SQS del camino entre EventBridge y Lambda para evitar el coste del polling continuo.
- Se sustituyó por monitorización activa de métricas como AsyncEventsDropped y ConcurrentExecutions, para mantenerse dentro de cuota sin perder eventos.
- Se centralizó el Dead Letter Queue: sondear un DLQ por cuenta reintroducía el mismo problema de coste, así que los fallos se enrutan a un DLQ centralizado.
- Esto exige disciplina extra, porque eventos de distintos tenants convergen en un único punto de recuperación — el ID de cuenta pasa a tratarse como ID de tenant dentro de ese modelo puente.
Industrializar el motor de despliegue
Un microservicio típico en esta plataforma implica decenas de funciones Lambda, reglas de EventBridge, tablas DynamoDB y máquinas de estado de Step Functions. Multiplicado por miles de cuentas, la complejidad de despliegue crece muy rápido. A escala de un millón de funciones, CloudFormation StackSets empezó a chocar con un techo de rendimiento y a producir errores que, en volumen, se volvían significativos.
En lugar de resignarse, el equipo empezó a construir un sistema de despliegue serverless propio. Eso llamó la atención del propio equipo de servicio de AWS CloudFormation, que se comprometió a dar soporte a ese caso de uso a la escala requerida. De ahí salieron dos cosas: aportar requisitos reales de escala que ayudaron a priorizar mejoras de estabilidad de StackSets, y construir un servicio propio de seguimiento de despliegues que agrega eventos de StackSets vía EventBridge, con una máquina de estados de Step Functions actuando como panel único de control ante fallos y reintentos.
Gobernanza madura y FinOps: el mono-repo
Operar una plataforma serverless a esta escala con un equipo pequeño exige gobernanza consistente, tanto a nivel cloud como de prácticas de ingeniería. Consolidar 20 microservicios en un único mono-repo permitió forzar herramientas y escaneo de seguridad consistentes en más de un millón de funciones, coordinar actualizaciones de runtime y librerías desde una única fuente de verdad, y asegurar que cada cambio pasa por la misma cadena CI/CD con compatibilidad garantizada.
La disciplina de optimización de costes también cambia con la madurez: al principio son tareas de limpieza y ahorros fáciles; más adelante se convierte en cambios arquitectónicos genuinamente complejos cuando una nueva feature dispara el número de invocaciones y el coste.
La realidad del "casi cero"
Incluso con un mandato estricto de scale-to-zero, la conclusión fue que "cero" en la práctica suele ser "casi cero". Evitar NAT Gateways no elimina otros costes de monitorización, como las alarmas de CloudWatch o la agregación de métricas en herramientas externas de observabilidad — lo que el equipo llamó el "impuesto de la monitorización". Optimizando de forma agresiva esos costes, lograron bajar el coste de una cuenta inactiva a menos de 1 dólar al mes.
Otro hábito clave: resistir el impulso de escribir una función Lambda nueva por defecto. Antes de abrir el editor, merece la pena preguntarse si un servicio gestionado nativo —como EventBridge Pipes, AppSync o colas SQS FIFO— ya resuelve el problema sin código adicional que mantener.
Mi lectura como arquitecto cloud
Lo que más me interesa de este caso no es el número final —un millón de funciones suena vistoso, pero es un efecto secundario, no el objetivo— sino la secuencia de decisiones. Cada fase resuelve exactamente el problema que toca en ese momento, ni antes ni después: StackSets tiene sentido con decenas de cuentas y deja de tenerlo con miles; SQS tiene sentido como patrón de resiliencia estándar y deja de tenerlo cuando el coste de polling constante supera el valor que aporta.
Para equipos de Cloud Operations y Platform Engineering, la lección de fondo es que la eficiencia tiene que escalar más rápido que el crecimiento. No basta con que la arquitectura funcione a mil cuentas: hay que diseñar sabiendo que las decisiones que hoy son cómodas pueden ser insostenibles dentro de un año, y dejar puntos de control (métricas de coste por cuenta, cuotas, jitter) que avisen antes de que el problema se convierta en incidente.
Cuándo sí aplicaría este patrón
- Cuando construyo una plataforma SaaS multi-tenant y necesito aislamiento real de seguridad y cuotas entre clientes.
- Cuando el número de cuentas o funciones va a crecer de forma sostenida, no puntual.
- Cuando el equipo puede invertir en automatización de aprovisionamiento desde el principio, en vez de crear cuentas a mano.
- Cuando existe capacidad real de monitorizar coste por cuenta de forma granular y actuar sobre ello.
Cuándo tendría cuidado o elegiría otra opción
- Si la plataforma tiene pocos clientes y un modelo multi-cuenta añade complejidad organizativa innecesaria.
- Si el equipo no tiene capacidad para mantener un account factory ni gobernanza vía AWS Organizations.
- Si se adoptan patrones "best practice" (como SQS entre todo) sin medir su coste real a la escala propia.
- Si no hay presupuesto de tiempo de ingeniería para tratar la observabilidad como coste gestionado activamente, no como gasto fijo aceptado sin más.
Conclusión
Escalar de 0 a 1 millón de funciones Lambda en miles de cuentas de AWS no es una historia sobre capacidad técnica: es una historia sobre eficiencia. El aislamiento por cuenta, el scale-to-zero real, la gestión proactiva de cuotas, la colaboración temprana con los equipos de servicio de AWS y una disciplina de ingeniería consistente son las piezas que sostienen ese crecimiento sin que el coste ni la complejidad se disparen antes que el negocio.
La idea que me llevo de este caso es esta: en serverless a gran escala, cada patrón "best practice" tiene una fecha de caducidad, y saber cuándo dejar de aplicarlo importa tanto como saber cuándo adoptarlo.
Después de hablar de AWS, Lambda y arquitectura serverless, también viene bien salir de la pantalla. Descubre Uzbekistán con Viajar por la Ruta de la Seda y recorre una de las regiones más fascinantes de Asia Central.
Historia, arquitectura y una ruta perfecta para cambiar de contexto después de tanto cloud.