En su artículo "Stop Chasing Idle Servers: Intent-Aware FinOps for the Real World", el director general de DoiT, Vadim Solovey, destacó una importante realidad de la computación en nube: Una "ilusión de eficiencia" puede enmascarar un despilfarro significativo. Aunque los recursos ociosos son fáciles de detectar, algunas de las ineficiencias más costosas se esconden dentro de tu organización de ingeniería o código, lugares donde la reconfiguración de la nube por sí sola no puede resolver el problema.

Este artículo se centra específicamente en los casos en los que el código es el culpable. No siempre es fácil llevar la investigación del nivel de la nube al nivel del código. Presentaré una metodología.
Un enfoque sistemático para la optimización de los costes de la nube
Paso 1: Identifica tus mayores centros de costes
La optimización de los costes de la nube sigue el Principio de Pareto (80/20): un pequeño porcentaje de tus recursos suele representar la mayor parte de tus costes. Empieza por utilizar herramientas como DoiT Cloud Intelligence™ para identificar tus mayores áreas de gasto.
Paso 2: Obtén ventajas administrativas rápidas
Antes de sumergirte en las optimizaciones de código, aborda primero los ajustes de administración de la nube más sencillos:
- Dimensionar correctamente las instancias infrautilizadas
- Eliminar recursos huérfanos
- Implementar niveles de almacenamiento adecuados
- Ajustar los parámetros de autoescalado
Son menos costosos que sumergirse en el código.
Paso 3: Busca indicadores de ineficacia a nivel de código
Una vez completadas las optimizaciones administrativas, examina los recursos de alto coste en busca de posibles ineficiencias impulsadas por el código.
Debido a la "ilusión de eficiencia", estos indicadores pueden ser sutiles. Los escenarios del mundo real que se analizan más adelante en este artículo ilustran las señales reveladoras más comunes a las que hay que estar atento, y que a menudo se encuentran utilizando herramientas estándar de supervisión de la nube en las consolas de GCP, AWS y Azure.
Paso 4: Investigar: Perfilar y analizar
Pasa del nivel de la nube al nivel del código utilizando herramientas de elaboración de perfiles de ejecución que pueden ejecutarse en la nube.
- Para bases de datos: Analizadores de consultas y perspectivas de rendimiento de la Consola en la Nube
- Para aplicaciones: Perfiladores y analizadores de memoria específicos del lenguaje
- Para canalizaciones de datos: Gráficos de ejecución y métricas de distribución

Implementar esto puede ser fácil, como en el caso de SQL, donde se proporcionan herramientas en la nube, o difícil, como en el caso del perfilado de memoria de Python en aplicaciones distribuidas que se ejecutan en entornos gestionados.
Paso 5: Poner en práctica, medir, validar
Soluciona los problemas identificados, vuelve a desplegar y mide las mejoras técnicas utilizando las consolas en la nube de AWS, GCP y Azure; revisa los informes de costes de Cloud Intelligence™ para validar las mejoras de costes.
Escenarios reales y soluciones
Escenario 1: Microservicio Java con fugas de memoria
Lo que parecía eficiente: Un microservicio Java Lambda que mantiene una utilización de memoria del 70-100%, maximizando aparentemente la asignación de recursos.
La realidad: La aplicación sufría fugas de memoria en las que un objeto global mantenía cadenas de referencia que retenían objetos entre invocaciones. Las caídas ocasionales y las sustituciones de instancias eran lo suficientemente infrecuentes como para escapar a la atención de la SRE.
La pista: La monitorización reveló un patrón de uso de memoria en diente de sierra a lo largo del tiempo. La investigación de las caídas en ese diente de sierra condujo a los registros de CloudWatch, que mostraban bloqueos periódicos.
Investigación: Se activó el perfilador CodeGuru, que reveló un uso creciente de memoria con el tiempo. Las investigaciones fuera de línea con un perfilador JVM identificaron una retención de objetos inesperada.
Solución: Código modificado para liberar las referencias a objetos al final de cada petición web.
Resultado: Uso estable de la memoria, menos sustituciones de instancias y menores costes de recursos.
Escenario 2: Proceso de datos Java con estructuras de datos ineficientes
Lo que parecía eficiente: Una canalización de flujo de datos con contenedores Java personalizados que procesan millones de registros al día con una utilización de la CPU elevada y constante.
La realidad: El código utilizaba estructuras de datos ineficaces, incluidos mapas con concatenación innecesaria de cadenas de datos por objeto en bucles cerrados, lo que creaba una sobrecarga excesiva de recogida de basura.
La pista: El elevado uso de recursos sugería la necesidad de una investigación más profunda.
Investigación: Se añadió GCP Cloud Profiler al contenedor. Esto mostró un escalado superlineal del tiempo y del uso de memoria con conjuntos de datos más grandes.
Solución:
- Sustituye los mapas por objetos personalizados que contengan sólo la información necesaria.
- Implementada la unión de cadenas adecuada en lugar de la concatenación repetida
Resultado: un 50% menos de uso de memoria y un 70% de reducción del tiempo de procesamiento, lo que permite tener máquinas de trabajo más pequeñas y menos instancias.
Escenario 3: Estructuras de datos en memoria que provocan máquinas virtuales sobredimensionadas
Lo que parecía eficiente: Las máquinas virtuales de gran memoria parecían rentables en comparación con las soluciones de escala horizontal, y las estructuras de datos Python en memoria ofrecían ventajas de velocidad algorítmica sobre las consultas a bases de datos.
La realidad: Este planteamiento creaba múltiples ineficiencias:
- Los proveedores de la nube imponen relaciones mínimas entre CPU y memoria, lo que da lugar a una capacidad de CPU cara y sin utilizar.
- Las asignaciones de memoria vienen en incrementos predefinidos, requiriendo un pago por la capacidad de memoria intermedia no utilizada.
- Los largos tiempos de inicialización hicieron necesario mantener varias instancias costosas funcionando simultáneamente para mayor robustez.
La pista: DoiT Cloud Intelligence™ mostró que una gran fracción del gasto total procedía de máquinas virtuales ultra grandes, lo que suele ser un indicador de un estado problemático en las arquitecturas de nube.
Investigación: El análisis profundo de los algoritmos reveló oportunidades para refactorizar y permitir el almacenamiento de datos fuera de la memoria de la aplicación.
Solución:
- Algoritmos refactorizados para trabajar con conjuntos de datos parciales consultados desde bases de datos, según sea necesario
- Implementación de una base de datos NoSQL con Redis como caché en memoria
- Cuando se necesitaba una precarga de datos completa para los datos de referencia clave, las estructuras de datos optimizadas en Redis permitían una menor huella de memoria que los objetos en la memoria de la aplicación
Resultado: Este cambio de arquitectura redujo significativamente el tamaño de las máquinas virtuales, permitiendo el escalado horizontal y reduciendo radicalmente los costes, aunque requirió un importante esfuerzo de ingeniería.
Revisión de casos anteriores
Volvamos a otros dos ejemplos del artículo que he mencionado antes, "Deja de perseguir servidores inactivos", y veamos cómo encajan en este marco.
Escenario 4: Base de datos empujando al 85% de IOPS
Lo que parecía eficiente: La instancia RDS parecía totalmente utilizada, lo que sugería una asignación óptima de recursos.
La realidad: Cada consulta realizaba escaneos de tabla completa porque faltaban dos índices críticos, lo que aumentaba drásticamente los requisitos de recursos.
La pista: Dado que la mayoría de las consultas SQL no deberían requerir un uso elevado de recursos (salvo en procesos por lotes muy ajustados), un patrón de alta utilización indicaba oportunidades de optimización.
Investigación: Se identificaron las consultas problemáticas y los índices que faltaban, utilizando el Optimizador de Rendimiento de AWS RDS, activado de forma predeterminada en la Consola de AWS. (GCP tiene el similar Cloud SQL Query Insights).
Solución: Añadidos los índices que faltaban.
Resultado: una reducción de 10 veces en la latencia de las consultas y la posibilidad de reducir el tamaño de la base de datos en dos niveles.
Escenario 5: Trabajo Spark al 70% de CPU durante cuatro horas cada noche
Lo que parecía eficiente: El clúster mantenía una elevada utilización de la CPU, lo que sugería una adecuada asignación de recursos.
La realidad: el 80% de los datos se concentraba en una sola clave sesgada, lo que creaba tareas rezagadas que prolongaban considerablemente el tiempo de procesamiento.
La pista: El problema empezó en un momento concreto sin ninguna otra causa clara. (Más tarde resultó corresponder a la llegada de nuevos datos con la "tecla rápida").
Investigación: El código Spark se ejecuta en un entorno altamente distribuido, lo que dificulta el uso de un perfilador ordinario que puedas utilizar para aplicaciones. Ésta es una buena razón para mantener la lógica centrada en transformaciones sencillas en lugar de en lógica empresarial compleja. Sin embargo, al utilizar la interfaz de usuario de Spark para analizar la distribución de tareas entre etapas, se identificaron rezagados. La monitorización de BigTable reveló "claves calientes" en la base de datos que se estaba procesando.
Solución: Repartir y salar la clave problemática para distribuir la carga de trabajo de forma más uniforme.
Resultado: El tiempo de finalización del trabajo disminuyó de 4 horas a 45 minutos, y el tamaño necesario del clúster se redujo en dos tercios.
Conclusión
Lograr una verdadera eficiencia de la nube a veces requiere ir más allá de las configuraciones de la nube y abordar también las ineficiencias a nivel del código. Cuando el código es la causa fundamental del exceso de costes de la nube, los ajustes de infraestructura por sí solos no solucionarán el problema.
Si asocias a tu equipo de desarrollo con FinOps y SRE, podrás identificar y resolver estas ineficiencias ocultas mediante un enfoque sistemático:
- Empieza por las áreas de mayor gasto que muestra la analítica de costes.
- En primer lugar, aborda las victorias rápidas en el nivel de configuración de la nube.
- En las Consolas Nube, busca pistas reveladoras que sugieran una investigación más profunda.
- Utiliza herramientas adecuadas de elaboración de perfiles, preferiblemente en la nube pero sin conexión si es necesario, para localizar las ineficiencias.
- Corrige el código, vuelve a desplegarlo y valida las mejoras de costes.
Este enfoque colaborativo no sólo reduce los costes, sino que a menudo mejora también el rendimiento y la fiabilidad de las aplicaciones: una ganancia tanto para tu presupuesto como para tus usuarios.
En el equipo de Ingeniería de Fiabilidad del Cliente de DoiT, guío a las organizaciones a través de todo el viaje de optimización. Aprovechando DoiT Cloud Intelligence™ y décadas de experiencia, ayudamos a identificar posibles ganancias, describir correcciones a nivel de nube, descubrir ilusiones de eficiencia y validar el impacto de las mejoras a nivel de código. Ponte en contacto con nosotros en doit.com/services


