\n\n\n\n Mis facturas de la nube son demasiado altas: lo que estoy viendo ahora - AgntMax \n

Mis facturas de la nube son demasiado altas: lo que estoy viendo ahora

📖 13 min read2,510 wordsUpdated Mar 26, 2026

¡Hola a todos! Jules Martin aquí, de nuevo en agntmax.com.

Hoy quiero hablar sobre algo que me ha estado preocupando, y probablemente a muchos de ustedes, durante el último año más o menos: el aumento constante del costo de la infraestructura en la nube, especialmente cuando se trata de funciones sin servidor. Todos hemos caído ante el sueño de “paga por lo que usas”, y durante mucho tiempo, se sintió como una realidad. Pero últimamente, he visto cómo las facturas aumentan, a veces inexplicablemente, incluso cuando los patrones de tráfico parecen estables. Es como si nos estuvieran cobrando por la misma flexibilidad que adoptamos. Así que, profundicemos en algo muy específico y oportuno: Domando al Monstruo Sin Servidor: Revelando y Reduciendo los Costos Ocultos de AWS Lambda.

Mi propia aventura en esto comenzó hace unos seis meses. Tenemos un microservicio central que maneja la autenticación de usuarios y la gestión de sesiones. Está construido casi en su totalidad sobre AWS Lambda, API Gateway, DynamoDB y Cognito. Durante mucho tiempo, los costos eran perfectamente predecibles. Luego, el verano pasado, nuestra factura de AWS para ese servicio específico aumentó alrededor del 15%. Sin nuevas características, sin picos de tráfico significativos. Inicialmente lo atribuí a alguna fluctuación estacional o un pequeño error que aún no había encontrado. Pero cuando llegó la factura del mes siguiente, aún más alta, supe que tenía que investigar. Esto no era solo un bache; era una tendencia, y nos estaba costando dinero real.

La Ilusión de los Niveles “Gratis” y la Realidad de las Invocaciones “Pequeñas”

Uno de los mayores puntos de venta de las funciones sin servidor, especialmente para startups o equipos más pequeños, es el generoso nivel gratuito. ¡Y es generoso! Un millón de invocaciones gratuitas al mes para Lambda, además de una cantidad significativa de tiempo de computación. El problema es que, a medida que tu aplicación crece, esas invocaciones “gratuitas” desaparecen más rápido que una porción de pizza en un encuentro tecnológico. Lo que a menudo se pasa por alto es el volumen de pequeñas invocaciones, aparentemente insignificantes, que se acumulan. Piensa en trabajos cron, revisiones internas de salud o incluso mecanismos de reintento de otros servicios. Cada una de esas cuenta.

Mi investigación en nuestro servicio de autenticación reveló exactamente esto. Teníamos una función de Lambda, llamémosla auth-token-refresher, diseñada para refrescar periódicamente los tokens de servicio internos. Estaba programada para ejecutarse cada cinco minutos. Parece inofensivo, ¿verdad? 288 invocaciones al día. Multiplica eso por 30 días y tienes 8,640 invocaciones al mes. Añade nuestros entornos de desarrollo, prueba y producción, y de repente son más de 25,000 invocaciones solo para una pequeña tarea de mantenimiento. Teníamos una docena de funciones así. De repente, nuestras invocaciones “pequeñas” ya no eran tan pequeñas.

Encontrando a los Culprit: Las Métricas de CloudWatch son Tu Mejor Amigo

El primer paso para domar a esta bestia es saber a dónde va tu dinero. AWS CloudWatch es indispensable aquí. No te limites a mirar el panel de control de facturación general; profundiza en las métricas específicas de tus funciones de Lambda.

Esto es en lo que me enfoqué:

  1. Invocaciones: Esta es la métrica más sencilla. Altos conteos de invocaciones para funciones que no manejan tráfico directo de usuarios son señales de alerta inmediatas.
  2. Duración: ¿Cuánto tiempo está ejecutándose cada invocación? Duraciones más largas significan mayores costos de computación.
  3. Uso de Memoria: ¿Estás sobreaprovisionando memoria para tus funciones? Pagas por lo que asignas, no por lo que usas.
  4. Tasa de Errores: Tasas de error altas pueden llevar a reintentos, lo que significa más invocaciones y ciclos de computación desperdiciados.

Para nuestro auth-token-refresher, miré su métrica de `Invocaciones`. Efectivamente, estaba funcionando como un reloj, cada cinco minutos. La duración era mínima, solo alrededor de 50 ms. Pero el volumen total estaba contribuyendo a nuestro costo general de invocaciones.

Ejemplo Práctico 1: Consolidando y Programando de Manera Más Inteligente

La solución para auth-token-refresher y varias otras funciones de mantenimiento similares fue sorprendentemente simple: consolidación. En lugar de tener funciones de Lambda individuales activadas por eventos de CloudWatch (o EventBridge en estos días) en horarios separados, creé una sola función de Lambda llamada “Mantenimiento Runner”.

Este “Mantenimiento Runner” es activado por una sola regla de eventos de CloudWatch, digamos, una vez por hora. Dentro de este runner, tengo un despachador simple que verifica la hora actual y ejecuta las tareas necesarias. Por ejemplo:


import os
import datetime

def lambda_handler(event, context):
 current_hour = datetime.datetime.now().hour
 current_minute = datetime.datetime.now().minute

 # Tarea 1: Refrescar token de autenticación (se ejecutaba cada 5 minutos)
 if current_minute % 10 == 0: # Ahora se ejecuta cada 10 minutos
 print("Ejecutando refresco de token de autenticación...")
 # Llama a la lógica de refresco de token o a otra función interna
 refresh_auth_token()

 # Tarea 2: Limpiar registros antiguos (se ejecutaba cada hora)
 if current_hour % 1 == 0 and current_minute == 0: # Se ejecuta a la hora en punto
 print("Ejecutando limpieza de registros...")
 cleanup_old_logs()

 # Tarea 3: Verificar estado del servicio externo (se ejecutaba cada 30 minutos)
 if current_minute == 0 or current_minute == 30:
 print("Verificando estado del servicio externo...")
 check_external_service()

 return {
 'statusCode': 200,
 'body': 'Tareas de mantenimiento ejecutadas.'
 }

def refresh_auth_token():
 # ... lógica real de refresco de token ...
 pass

def cleanup_old_logs():
 # ... lógica real de limpieza de registros ...
 pass

def check_external_service():
 # ... lógica real de verificación del servicio externo ...
 pass

Este cambio simple redujo inmediatamente el conteo de invocaciones para estas tareas de mantenimiento de cientos de miles al mes a unos pocos miles. Los ahorros en costos fueron tangibles, no solo en invocaciones de Lambda sino también en la ingestión de registros de CloudWatch y llamadas de API Gateway (si alguna de estas se exponía a través de API Gateway).

La Trampa de Sobreaprovisionamiento de Memoria

Este es otro impulsor de costo sutil que a menudo se pasa por alto. Cuando creas una función de Lambda, asignas una cierta cantidad de memoria (por ejemplo, 128MB, 256MB, 512MB). Pagas por esa memoria asignada, independientemente de cuánto use realmente tu función. Además, el poder de la CPU se escala proporcionalmente con la asignación de memoria. Así que, si asignas 1GB de memoria para un simple script de Python que solo necesita 128MB, no solo estás pagando de más por la memoria; también estás pagando de más por ciclos de CPU que no necesita.

Aprendí esto por las malas con una función de Lambda de procesamiento de datos que estaba inicialmente configurada con 1GB de memoria “por si acaso”. Cuando revisé sus métricas de CloudWatch para el uso de memoria, se mantenía constantemente por debajo de 200MB, incluso durante cargas máximas. Esencialmente estábamos pagando por 800MB de RAM no utilizada y el aumento de CPU correspondiente.

Ejemplo Práctico 2: Optimizando la Asignación de Memoria con Lambda Power Tuning

Descubrir manualmente la configuración óptima de memoria puede ser tedioso. Tienes que desplegar, probar, monitorear, ajustar y repetir. Afortunadamente, hay una herramienta de código abierto fantástica llamada AWS Lambda Power Tuning (desarrollada por Alex Casalboni en AWS) que hace que este proceso sea sencillo.

Es una aplicación sin servidor que te ayuda a visualizar e identificar la configuración óptima de memoria para tus funciones de Lambda en función del costo y el rendimiento. La despliegas en tu cuenta de AWS y luego la puedes usar para probar tus funciones.

Así es como funciona generalmente:

  1. Despliegas la herramienta Power Tuning a través del Repositorio de Aplicaciones Sin Servidor o SAM.
  2. Invocas una máquina de estados (creada por la herramienta) con el ARN de tu función de Lambda y una carga útil.
  3. La máquina de estados invoca múltiples veces tu Lambda con diferentes configuraciones de memoria (por ejemplo, 128MB, 256MB, 512MB, 1024MB, etc.).
  4. Luego analiza los registros de ejecución y proporciona una visualización que muestra los compromisos de costo y velocidad para cada configuración de memoria.

Para mi función de procesamiento de datos, ejecutarla a través del Power Tuner mostró que 256MB era el punto óptimo en costo, con una degradación de rendimiento despreciable en comparación con 1GB. Inmediatamente redujimos la asignación de memoria a 256MB, lo que resultó en una reducción del 75% en el costo de computación para esa función específica. Esto no fue un acontecimiento aislado; desde entonces, he hecho una práctica estándar de pasar nuevas funciones o aquellas reevaluadas a través de esta herramienta.

Para usarla, después del despliegue, normalmente iniciarías la máquina de estados con algo como esto (ajustando ARN y carga útil):


aws stepfunctions start-execution \
 --state-machine-arn "arn:aws:states:REGION:ACCOUNT_ID:stateMachine:powerTuningStateMachine" \
 --input '{ "lambdaARN": "arn:aws:lambda:REGION:ACCOUNT_ID:function:YOUR_FUNCTION_NAME", "num": 100, "payload": {}, "parallel": 5 }'

La salida proporciona un gráfico claro, mostrando exactamente dónde se intersectan tu costo y velocidad para un rendimiento óptimo. Es un cambio significativo para la optimización de costos.

Verbosos de Registro y Arranques en Frío

Otras dos áreas que a menudo se presentan son la verbosidad de los registros y los arranques en frío. Los registros de CloudWatch no son gratuitos. Cada línea que imprime tu función de Lambda se ingresa y se almacena, y por eso pagas. Si bien un buen registro es crucial para la depuración, un registro excesivamente verboso (por ejemplo, imprimir objetos completos o repetir mensajes de estado innecesariamente) puede inflar rápidamente tu factura de logs de CloudWatch.

Encontré algunas funciones que estaban registrando el cuerpo completo de la solicitud HTTP en cada invocación. Aunque útil para el desarrollo inicial, en producción, esto solo era ruido y costo. Un ajuste rápido para registrar solo los metadatos esenciales (ID de solicitud, código de estado, punto final) redujo drásticamente nuestra ingestión de registros.

Los inicios en frío, aunque no son un “costo” directo de la misma manera, impactan la experiencia del usuario y pueden llevar indirectamente a más reintentos o a duraciones de facturación más largas si tu función tiene que esperar recursos. Aunque AWS ha hecho avances significativos en la reducción de los tiempos de inicio en frío, optimizar el tamaño del paquete de tu función y evitar lógica de inicialización compleja fuera del controlador aún puede marcar la diferencia. Para funciones críticas y sensibles a la latencia, la concurrencia provisionada es una opción, pero ten en cuenta que pagas por esa concurrencia asignada incluso cuando está inactiva.

Ejemplo Práctico 3: Registro Inteligente y Variables de Entorno

Para el registro, la solución más sencilla a menudo es la mejor. Utiliza variables de entorno para controlar los niveles de registro. En Python, por ejemplo, puedes hacer lo siguiente:


import os
import logging

LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO').upper()
logging.basicConfig(level=LOG_LEVEL)
logger = logging.getLogger()

def lambda_handler(event, context):
 logger.debug("Este es un mensaje de depuración, visible solo si LOG_LEVEL es DEBUG")
 logger.info("Procesando evento: %s", event.get('request_id'))
 try:
 # ... lógica de la función ...
 logger.debug("Terminada la procesamiento para request_id: %s", event.get('request_id'))
 return {
 'statusCode': 200,
 'body': 'Éxito'
 }
 except Exception as e:
 logger.error("Error al procesar request_id %s: %s", event.get('request_id'), str(e), exc_info=True)
 return {
 'statusCode': 500,
 'body': 'Error'
 }

Al establecer LOG_LEVEL en INFO en producción y DEBUG en desarrollo/etapa, puedes reducir significativamente tu factura de CloudWatch Logs sin sacrificar la observabilidad cuando la necesitas.

Otro truco es ser consciente de lo que se inicializa fuera del controlador. Cualquier código directamente en el ámbito global de tu función Lambda se ejecutará durante el inicio en frío. Si tienes operaciones costosas como agrupamiento de conexiones a bases de datos o importaciones de bibliotecas grandes, considera diferenciarlas hasta que realmente se necesiten dentro del controlador, o asegúrate de que estén en caché de manera eficiente para invocaciones posteriores en caliente.

Conclusiones Accionables para Tu Cruzada de Costos Serverless

Bien, hemos cubierto bastante. Aquí tienes un resumen de pasos prácticos que puedes tomar ahora mismo para empezar a reducir esos costos ocultos de Lambda:

  • Monitorea incansablemente: No solo eches un vistazo a tu factura general de AWS. Profundiza en las métricas de CloudWatch para Invocaciones, Duración y Uso de Memoria de cada función Lambda. Configura alarmas para picos inesperados.
  • Consolida trabajos programados: Si tienes muchas funciones Lambda pequeñas y programadas, considera combinarlas en un solo “Mantenimiento Runner” que despache tareas según un horario más infrecuente. Esto reduce drásticamente las cuentas de invocación.
  • Optimiza la asignación de memoria: Utiliza herramientas como AWS Lambda Power Tuning para encontrar la configuración de memoria óptima para tus funciones. No supongas y sobre-asignes. Recuerda que más memoria significa más CPU, y pagas por ambas.
  • Controla la verbosidad del registro: Implementa niveles de registro impulsados por variables de entorno (por ejemplo, INFO para producción, DEBUG para desarrollo). Evita registrar cuerpos de solicitud enteros o el estado interno excesivo en producción. Tu factura de CloudWatch Logs te lo agradecerá.
  • Revisa funciones no utilizadas: Audita periódicamente tus funciones Lambda. ¿Hay funciones antiguas, experimentales o en desuso aún activas que generen costos? ¡Eliminarlas!
  • Presta atención al tamaño del paquete: Paquetes de implementación más pequeños significan inicios en frío más rápidos y menos costo de almacenamiento. Incluye solo las dependencias necesarias.
  • Comprende tu modelo de precios: Relee la página de precios de Lambda. Comprende cómo se facturan las invocaciones, GB-segundos y la transferencia de datos. El conocimiento es poder, especialmente cuando se trata de tu billetera.

Dominar el monstruo serverless no se trata de evitarlo; se trata de ser inteligente e intencional con cómo lo usamos. La flexibilidad y escalabilidad son invaluables, pero sin la vigilancia adecuada, esos costos “pequeños” pueden sumar una parte significativa de tu presupuesto. ¡Ve adelante, monitorea, optimiza y ahorra!

Eso es todo por hoy. ¡Déjame saber en los comentarios si tienes algún otro consejo o truco para la optimización de costos de Lambda!

🕒 Published:

✍️
Written by Jake Chen

AI technology writer and researcher.

Learn more →
Browse Topics: benchmarks | gpu | inference | optimization | performance
Scroll to Top