Este principio del pilar de sustentabilidad del Google Cloud Framework de Well-Architected proporciona recomendaciones para escribir software que minimice el consumo de energía y la carga del servidor.
Descripción general del principio
Cuando sigues las prácticas recomendadas para compilar tus aplicaciones en la nube, optimizas la energía que utilizan los recursos de infraestructura de la nube: IA, procesamiento, almacenamiento y red. También ayudas a reducir los requisitos de agua de los centros de datos y la energía que consumen los dispositivos de los usuarios finales cuando acceden a tus aplicaciones.
Para crear software eficiente en el uso de energía, debes integrar consideraciones de sustentabilidad en todo el ciclo de vida del software, desde el diseño y el desarrollo hasta la implementación, el mantenimiento y el archivado. Para obtener orientación detallada sobre cómo usar la IA para compilar software que minimice el impacto ambiental de las cargas de trabajo en la nube, consulta el Google Cloud libro electrónicoBuild Software Sustainably.
Recomendaciones
Las recomendaciones de esta sección se agrupan en las siguientes áreas de enfoque:
- Minimiza el trabajo computacional: Prefiere el código eficiente y enfocado que elimina la lógica redundante y evita los cálculos innecesarios o el exceso de funciones.
- Usa algoritmos y estructuras de datos eficientes: Elige algoritmos eficientes en términos de tiempo y memoria que reduzcan la carga de la CPU y minimicen el uso de memoria.
- Optimiza las operaciones de procesamiento y datos: Desarrolla con el objetivo de usar de manera eficiente todos los recursos disponibles, incluidos la CPU, la memoria, la E/S de disco y la red. Por ejemplo, cuando reemplazas los bucles de espera con lógica basada en eventos, evitas el sondeo innecesario.
- Implementa la optimización del frontend: Para reducir la energía que consumen los dispositivos de los usuarios finales, usa estrategias como la minimización, la compresión y la carga diferida de imágenes y recursos.
Minimiza el trabajo computacional
Para escribir software eficiente en términos de energía, debes minimizar la cantidad total de trabajo computacional que realiza tu aplicación. Cada instrucción innecesaria, bucle redundante y función adicional consume energía, tiempo y recursos. Usa las siguientes recomendaciones para compilar software que realice cálculos mínimos.
Escribe código eficiente y enfocado
Para escribir el código mínimo que es esencial para lograr los resultados requeridos, usa los siguientes enfoques:
- Elimina la lógica redundante y el exceso de funciones: Escribe código que solo realice las funciones esenciales. Evita las funciones que aumentan la sobrecarga y la complejidad computacionales, pero no proporcionan un valor medible para tus usuarios.
- Refactoriza: Para mejorar la eficiencia energética con el tiempo, audita periódicamente tus aplicaciones para identificar las funciones que no se usan. Toma medidas para quitar o refactorizar esas funciones según corresponda.
- Evita operaciones innecesarias: No calcules un valor ni ejecutes una acción hasta que se necesite el resultado. Usa técnicas como la evaluación diferida, que retrasa los cálculos hasta que un componente dependiente de la aplicación necesite el resultado.
- Prioriza la legibilidad y la reutilización del código: Escribe código que sea legible y reutilizable. Este enfoque minimiza la duplicación y sigue el principio de no repetición (DRY), que puede ayudar a reducir las emisiones de carbono del desarrollo y el mantenimiento de software.
Usa el almacenamiento en caché de backend
El almacenamiento en caché del backend garantiza que una aplicación no realice el mismo trabajo de forma repetida. Una proporción alta de aciertos de caché genera una reducción casi lineal en el consumo de energía por solicitud. Para implementar el almacenamiento en caché del backend, usa las siguientes técnicas:
- Almacena en caché los datos frecuentes: Almacena los datos a los que se accede con frecuencia en una ubicación de almacenamiento temporal de alto rendimiento. Por ejemplo, usa un servicio de almacenamiento en caché en la memoria, como Memorystore. Cuando una aplicación recupera datos de una caché, se reduce el volumen de consultas de bases de datos y operaciones de E/S de disco. En consecuencia, disminuye la carga en las bases de datos y los servidores del backend.
- Almacena en caché las respuestas de la API: Para evitar llamadas de red redundantes y costosas, almacena en caché los resultados de las solicitudes frecuentes a la API.
- Prioriza el almacenamiento en caché en la memoria: Para eliminar las operaciones lentas de E/S de disco y las consultas complejas de bases de datos, almacena los datos en la memoria de alta velocidad (RAM).
- Selecciona las estrategias de escritura en caché adecuadas:
- La estrategia de escritura directa garantiza que los datos se escriban de forma síncrona en la caché y en el almacén persistente. Esta estrategia aumenta la probabilidad de aciertos de caché, por lo que el almacenamiento persistente recibe menos solicitudes de lectura que consumen mucha energía.
- La estrategia de escritura diferida (write-behind) mejora el rendimiento de las aplicaciones con muchas operaciones de escritura. Los datos se escriben primero en la caché y, luego, la base de datos se actualiza de forma asíncrona. Esta estrategia reduce la carga de escritura inmediata en las bases de datos más lentas.
- Usa políticas de descarte inteligentes: Mantén la caché optimizada y eficiente. Para quitar los datos inactivos o de baja utilidad y maximizar el espacio disponible para los datos solicitados con frecuencia, usa políticas como el tiempo de actividad (TTL), el uso menos reciente (LRU) y el uso menos frecuente (LFU).
Usa algoritmos y estructuras de datos eficientes
Los algoritmos y las estructuras de datos que elijas determinarán la complejidad computacional sin procesar de tu software. Cuando seleccionas algoritmos y estructuras de datos adecuados, minimizas la cantidad de ciclos de CPU y operaciones de memoria que se requieren para completar una tarea. Menos ciclos de CPU y operaciones de memoria generan un menor consumo de energía.
Elige algoritmos para una complejidad temporal óptima
Prioriza los algoritmos que logran el resultado requerido en la menor cantidad de tiempo. Este enfoque ayuda a reducir la duración del uso de recursos. Para seleccionar algoritmos que optimicen el uso de recursos, usa los siguientes enfoques:
- Enfócate en reducir la complejidad: Para evaluar la complejidad, considera la complejidad teórica del algoritmo, más allá de las métricas de tiempo de ejecución. Por ejemplo, en comparación con la ordenación de burbuja, la ordenación por fusión reduce significativamente la carga computacional y el consumo de energía para los conjuntos de datos grandes.
- Evita el trabajo redundante: Usa funciones integradas y optimizadas en el lenguaje de programación o el framework que elijas. Estas funciones suelen implementarse en un lenguaje de nivel inferior y más eficiente en términos de energía, como C o C++, por lo que están mejor optimizadas para el hardware subyacente en comparación con las funciones codificadas de forma personalizada.
Selecciona estructuras de datos para lograr eficiencia
Las estructuras de datos que elijas determinarán la velocidad a la que se pueden recuperar, insertar o procesar los datos. Esta velocidad afecta el uso de CPU y memoria. Para seleccionar estructuras de datos eficientes, usa los siguientes enfoques:
- Optimiza la búsqueda y la recuperación: Para las operaciones comunes, como verificar si existe un elemento o recuperar un valor específico, prefiere las estructuras de datos optimizadas para la velocidad. Por ejemplo, los mapas de hash o los conjuntos de hash permiten búsquedas en tiempo casi constante, lo que es un enfoque más eficiente en términos de energía que buscar linealmente en un array.
- Minimiza la huella de memoria: Las estructuras de datos eficientes ayudan a reducir la huella de memoria general de una aplicación. La reducción del acceso y la administración de la memoria genera un menor consumo de energía. Además, un perfil de memoria más eficiente permite que los procesos se ejecuten de manera más eficaz, lo que te permite posponer las actualizaciones de recursos.
- Usa estructuras especializadas: Utiliza estructuras de datos creadas específicamente para un problema determinado. Por ejemplo, usa una estructura de datos de árbol de prefijos para realizar búsquedas rápidas de prefijos de cadenas y una cola de prioridad cuando necesites acceder solo al valor más alto o más bajo de manera eficiente.
Optimiza las operaciones de procesamiento y datos
Cuando desarrolles software, enfócate en el uso eficiente y proporcional de los recursos en toda la pila de tecnología. Considera la CPU, la memoria, el disco y la red como recursos limitados y compartidos. Reconoce que el uso eficiente de los recursos genera reducciones tangibles en los costos y el consumo de energía.
Optimiza el uso de la CPU y el tiempo de inactividad
Para minimizar el tiempo que la CPU dedica a un estado activo que consume energía sin realizar un trabajo significativo, usa los siguientes enfoques:
- Prefiere la lógica controlada por eventos en lugar del sondeo: Reemplaza los bucles ocupados que consumen muchos recursos o la verificación constante (sondeo) con lógica controlada por eventos. Una arquitectura basada en eventos garantiza que los componentes de una aplicación solo funcionen cuando se activan por eventos relevantes. Este enfoque permite el procesamiento a pedido, lo que elimina la necesidad de sondeos que consumen muchos recursos.
- Evita la alta frecuencia constante: Escribe código que no fuerce a la CPU a funcionar constantemente a su frecuencia más alta. Para minimizar el consumo de energía, los sistemas inactivos deben poder entrar en estados de bajo consumo o modos de suspensión.
- Usa el procesamiento asíncrono: Para evitar que los subprocesos se bloqueen durante los tiempos de espera inactivos, usa el procesamiento asíncrono. Este enfoque libera recursos y genera un mayor uso general de los recursos.
Administra la memoria y las E/S del disco de manera eficiente
El uso ineficiente de la memoria y el disco genera un procesamiento innecesario y un mayor consumo de energía. Para administrar la memoria y las E/S de manera eficiente, usa las siguientes técnicas:
- Administración estricta de la memoria: Toma medidas para liberar de forma proactiva los recursos de memoria no utilizados. Evita mantener objetos grandes en la memoria durante períodos más largos de lo necesario. Este enfoque evita los cuellos de botella en el rendimiento y reduce la energía que se consume para el acceso a la memoria.
- Optimiza las E/S del disco: Reduce la frecuencia de las interacciones de lectura y escritura de tu aplicación con los recursos de almacenamiento persistente. Por ejemplo, usa un búfer de memoria intermedio para almacenar datos. Escribe los datos en el almacenamiento persistente en intervalos fijos o cuando el búfer alcanza un tamaño determinado.
- Operaciones por lotes: Consolida las operaciones de disco pequeñas y frecuentes en menos operaciones por lotes más grandes. Una operación por lotes consume menos energía que muchas transacciones pequeñas individuales.
- Usa compresión: Reduce la cantidad de datos que se escriben en los discos o se leen de ellos aplicando técnicas de compresión de datos adecuadas. Por ejemplo, para comprimir los datos que almacenas en Cloud Storage, puedes usar la transcodificación descompresiva.
Minimiza el tráfico de red
Los recursos de red consumen una cantidad significativa de energía durante las operaciones de transferencia de datos. Para optimizar la comunicación de red, usa las siguientes técnicas:
- Minimiza el tamaño de la carga útil: Diseña tus APIs y aplicaciones para transferir solo los datos necesarios para una solicitud. Evita recuperar o devolver estructuras JSON o XML grandes en los casos en que solo se requieren algunos campos. Asegúrate de que las estructuras de datos que se devuelven sean concisas.
- Reduce los viajes de ida y vuelta: Para reducir la cantidad de viajes de ida y vuelta de la red que se requieren para completar una acción del usuario, usa protocolos más inteligentes. Por ejemplo, prefiere HTTP/3 a HTTP/1.1, elige GraphQL en lugar de REST, usa protocolos binarios y consolida las llamadas a la API. Cuando reduces la cantidad de llamadas de red, disminuyes el consumo de energía tanto de tus servidores como de los dispositivos de los usuarios finales.
Implementa la optimización del frontend
La optimización del frontend minimiza los datos que deben descargar y procesar los usuarios finales, lo que ayuda a reducir la carga en los recursos de los dispositivos de los usuarios finales.
Minimiza el código y los recursos
Cuando los usuarios finales necesitan descargar y procesar recursos más pequeños y estructurados de manera más eficiente, sus dispositivos consumen menos energía. Para minimizar el volumen de descargas y la carga de procesamiento en los dispositivos de los usuarios finales, usa las siguientes técnicas:
- Minimización y compresión: En el caso de los archivos JavaScript, CSS y HTML, quita los caracteres innecesarios, como los espacios en blanco y los comentarios, con las herramientas de minimización adecuadas. Asegúrate de que los archivos, como las imágenes, estén comprimidos y optimizados. Puedes automatizar la minimización y la compresión de los recursos web con una canalización de CI/CD.
- Carga diferida: Carga imágenes, videos y recursos no críticos solo cuando sean necesarios, por ejemplo, cuando estos elementos se desplazan al viewport de una página web. Este enfoque reduce el volumen de transferencia de datos inicial y la carga de procesamiento en los dispositivos de los usuarios finales.
- Paquetes de JavaScript más pequeños: Elimina el código sin usar de tus paquetes de JavaScript con agrupadores de módulos modernos y técnicas como la eliminación de código no utilizado. Este enfoque genera archivos más pequeños que se cargan más rápido y usan menos recursos del servidor.
- Almacenamiento en caché del navegador: Usa encabezados de almacenamiento en caché HTTP para indicarle al navegador del usuario que almacene los recursos estáticos de forma local. El almacenamiento en caché del navegador ayuda a evitar descargas repetidas y tráfico de red innecesario en visitas posteriores.
Prioriza una experiencia del usuario (UX) ligera
El diseño de tu interfaz de usuario puede tener un impacto significativo en la complejidad computacional para renderizar el contenido del frontend. Para compilar interfaces de frontend que proporcionen una UX ligera, usa las siguientes técnicas:
- Renderización eficiente: Evita la manipulación frecuente y que requiere muchos recursos del Modelo de objetos del documento (DOM). Escribe código que minimice la complejidad de la renderización y elimine la volver a renderizar innecesaria.
- Patrones de diseño ligeros: Cuando sea apropiado, prefiere los sitios estáticos o las apps web progresivas (AWP). Estos sitios y apps se cargan más rápido y requieren menos recursos del servidor.
- Accesibilidad y rendimiento: Los sitios responsivos y de carga rápida suelen ser más sostenibles y accesibles. Un diseño optimizado y sin desorden reduce los recursos que se consumen cuando se renderiza el contenido. Los sitios web optimizados para el rendimiento y la velocidad pueden ayudar a generar mayores ingresos. Según un estudio de investigación de Deloitte y Google, Milliseconds Make Millions, una mejora de 0.1 segundos (100 ms) en la velocidad del sitio genera un aumento del 8.4% en las conversiones para los sitios de venta minorista y un aumento del 9.2% en el valor promedio del pedido.