Esse princípio no pilar de sustentabilidade do Google Cloud Well-Architected Framework fornece recomendações para escrever softwares que minimizem o consumo de energia e a carga do servidor.
Visão geral do princípio
Ao seguir as práticas recomendadas para criar aplicativos na nuvem, você otimiza a energia utilizada pelos recursos de infraestrutura em nuvem: IA, computação, armazenamento e rede. Você também ajuda a reduzir as necessidades de água dos data centers e a energia que os dispositivos do usuário final consomem ao acessar seus aplicativos.
Para criar um software com eficiência energética, é necessário integrar considerações de sustentabilidade em todo o ciclo de vida do software, desde o design e desenvolvimento até a implantação, manutenção e arquivamento. Para orientações detalhadas sobre como usar a IA para criar softwares que minimizem o impacto ambiental das cargas de trabalho na nuvem, consulte o Google Cloud e-book, Criar softwares de forma sustentável.
Recomendações
As recomendações nesta seção são agrupadas nas seguintes áreas de foco:
- Minimizar o trabalho computacional: favoreça um código enxuto e focado que elimine a lógica redundante e evite cálculos desnecessários ou inchaço de recursos.
- Usar algoritmos e estruturas de dados eficientes: escolha algoritmos eficientes em termos de tempo e memória que reduzam a carga da CPU e minimizem o uso da memória.
- Otimizar operações de computação e dados: desenvolva com o objetivo de usar com eficiência todos os recursos disponíveis, incluindo CPU, memória, E/S de disco e rede. Por exemplo, ao substituir loops ocupados por lógica orientada a eventos, você evita a pesquisa desnecessária.
- Implementar a otimização de front-end: Para reduzir a energia consumida pelos dispositivos do usuário final, use estratégias como minimização, compactação e carregamento lento para imagens e recursos.
Minimizar o trabalho computacional
Para escrever um software com eficiência energética, é necessário minimizar a quantidade total de trabalho computacional que o aplicativo realiza. Cada instrução desnecessária, loop redundante e recurso extra consome energia, tempo e recursos. Use as recomendações a seguir para criar softwares que realizem cálculos mínimos.
Escrever código enxuto e focado
Para escrever o código mínimo essencial para alcançar os resultados necessários, use as seguintes abordagens:
- Eliminar a lógica redundante e o inchaço de recursos: escreva um código que execute apenas as funções essenciais. Evite recursos que aumentem a sobrecarga computacional e a complexidade, mas não ofereçam valor mensurável aos usuários.
- Refatorar: para melhorar a eficiência energética ao longo do tempo, audite seus aplicativos regularmente para identificar recursos não utilizados. Entre em ação para remover ou refatorar esses recursos conforme apropriado.
- Evitar operações desnecessárias: não calcule um valor nem execute uma ação até que o resultado seja necessário. Use técnicas como a avaliação lenta, que atrasam os cálculos até que um componente dependente no aplicativo precise da saída.
- Priorizar a legibilidade e a reutilização do código: escreva um código legível e reutilizável. Essa abordagem minimiza a duplicação e segue o princípio "não se repita" (DRY, na sigla em inglês), o que pode ajudar a reduzir as emissões de carbono do desenvolvimento e da manutenção de softwares.
Usar o armazenamento em cache de back-end
O armazenamento em cache de back-end garante que um aplicativo não execute o mesmo trabalho repetidamente. Uma alta taxa de acertos de cache leva a uma redução quase linear no consumo de energia por solicitação. Para implementar o armazenamento em cache de back-end, use as seguintes técnicas:
- Armazenar dados frequentes: armazene dados acessados com frequência em um local de armazenamento temporário, de alta performance. Por exemplo, use um serviço de armazenamento em cache na memória, como o Memorystore. Quando um aplicativo recupera dados de um cache, o volume de consultas de banco de dados e operações de E/S de disco é reduzido. Consequentemente, a carga nos bancos de dados e servidores no back-end diminui.
- Armazenar respostas da API em cache: para evitar chamadas de rede redundantes e caras, armazene em cache os resultados de solicitações frequentes de API.
- Priorizar o armazenamento em cache na memória: para eliminar operações lentas de E/S de disco e consultas complexas de banco de dados, armazene dados em memória de alta velocidade (RAM).
- Selecionar estratégias de gravação de cache adequadas:
- A estratégia de gravação direta garante que os dados sejam gravados de forma síncrona no cache e no armazenamento persistente. Essa estratégia aumenta a probabilidade de acertos de cache, para que o armazenamento persistente receba menos solicitações de leitura com uso intensivo de energia.
- A estratégia de gravação de retorno (gravação atrasada) melhora a performance de aplicativos com muitas gravações. Os dados são gravados primeiro no cache, e o banco de dados é atualizado de forma assíncrona mais tarde. Essa estratégia reduz a carga de gravação imediata em bancos de dados mais lentos.
- Usar políticas de remoção inteligentes: mantenha o cache enxuto e eficiente. Para remover dados desatualizados ou de baixa utilidade e maximizar o espaço disponível para dados solicitados com frequência, use políticas como time to live (TTL), menos usado recentemente (LRU) e menos usado com frequência (LFU).
Usar algoritmos e estruturas de dados eficientes
Os algoritmos e as estruturas de dados escolhidos determinam a complexidade computacional bruta do software. Ao selecionar algoritmos e estruturas de dados adequados, você minimiza o número de ciclos de CPU e operações de memória necessárias para concluir uma tarefa. Menos ciclos de CPU e operações de memória levam a um menor consumo de energia.
Escolher algoritmos para complexidade de tempo ideal
Priorize algoritmos que alcancem o resultado necessário no menor tempo possível. Essa abordagem ajuda a reduzir a duração do uso de recursos. Para selecionar algoritmos que otimizem o uso de recursos, use as seguintes abordagens:
- Focar na redução da complexidade: para avaliar a complexidade, considere a complexidade teórica do algoritmo, além das métricas de execução. Por exemplo, quando comparado à classificação por bolha, classificação por mesclagem reduz significativamente a carga computacional e o consumo de energia para grandes conjuntos de dados.
- Evitar trabalho redundante: use funções integradas e otimizadas na sua linguagem de programação ou estrutura escolhida. Essas funções geralmente são implementadas em uma linguagem de nível inferior e mais eficiente em termos de energia, como C ou C++, portanto, são mais bem otimizadas para o hardware subjacente em comparação com funções codificadas personalizadas.
Selecionar estruturas de dados para eficiência
As estruturas de dados escolhidas determinam a velocidade com que os dados podem ser recuperados, inseridos ou processados. Essa velocidade afeta o uso da CPU e da memória. Para selecionar estruturas de dados eficientes, use as seguintes abordagens:
- Otimizar para pesquisa e recuperação: para operações comuns, como verificar se um item existe ou recuperar um valor específico, prefira estruturas de dados otimizadas para velocidade. Por exemplo, mapas de hash ou conjuntos de hash permitem pesquisas de tempo quase constante, que é uma abordagem mais eficiente em termos de energia do que pesquisar linearmente em uma matriz.
- Minimizar o consumo de memória: estruturas de dados eficientes ajudam a reduzir o consumo de memória geral de um aplicativo. O acesso e o gerenciamento de memória reduzidos levam a um menor consumo de energia. Além disso, um perfil de memória mais enxuto permite que os processos sejam executados com mais eficiência, o que permite adiar upgrades de recursos.
- Usar estruturas especializadas: use estruturas de dados que são criadas para um determinado problema. Por exemplo, use uma trie estrutura de dados para pesquisa rápida de prefixos de string e use uma fila de prioridade quando precisar acessar apenas o valor mais alto ou mais baixo de forma eficiente.
Otimizar operações de computação e dados
Ao desenvolver softwares, concentre-se no uso eficiente e proporcional de recursos em toda a pilha de tecnologia. Trate a CPU, a memória, o disco e a rede como recursos limitados e compartilhados. Reconheça que o uso eficiente de recursos leva a reduções tangíveis nos custos e no consumo de energia.
Otimizar a utilização da CPU e o tempo de inatividade
Para minimizar o tempo que a CPU gasta em um estado ativo e com consumo de energia sem realizar um trabalho significativo, use as seguintes abordagens:
- Preferir a lógica orientada a eventos em vez da pesquisa: substitua loops ocupados com uso intensivo de recursos ou verificação constante (pesquisa) por lógica orientada a eventos. Uma arquitetura orientada a eventos garante que os componentes de um aplicativo operem apenas quando são acionados por eventos relevantes. Essa abordagem permite o processamento sob demanda, o que elimina a necessidade de pesquisa com uso intensivo de recursos.
- Evitar alta frequência constante: escreva um código que não force a CPU a operar constantemente na frequência mais alta. Para minimizar o consumo de energia, os sistemas inativos precisam entrar em estados de baixa energia ou modos de suspensão.
- Usar o processamento assíncrono: para evitar que as linhas de execução sejam bloqueadas durante os tempos de espera inativa, use o processamento assíncrono. Essa abordagem libera recursos e leva a uma maior utilização geral de recursos.
Gerenciar a memória e a E/S de disco com eficiência
O uso ineficiente de memória e disco leva a processamento desnecessário e aumento do consumo de energia. Para gerenciar a memória e a E/S com eficiência, use as seguintes técnicas:
- Gerenciamento de memória estrito: Entre em ação para liberar proativamente recursos de memória não utilizados. Evite manter objetos grandes na memória por períodos mais longos do que o necessário. Essa abordagem evita gargalos de performance e reduz a energia consumida para acesso à memória.
- Otimizar a E/S de disco: reduza a frequência das interações de leitura e gravação do seu aplicativo com recursos de armazenamento persistente. Por exemplo, use um buffer de memória intermediário para armazenar dados. Grave os dados no armazenamento persistente em intervalos fixos ou quando o buffer atingir um determinado tamanho.
- Operações em lote: consolide operações de disco pequenas e frequentes em operações em lote maiores e menos frequentes. Uma operação em lote consome menos energia do que muitas transações pequenas e individuais.
- Usar compactação: reduza a quantidade de dados gravados ou lidos dos discos aplicando técnicas adequadas de compactação de dados. Por exemplo, para compactar dados armazenados no Cloud Storage, é possível usar a transcodificação descompressiva.
Minimizar o tráfego de rede
Os recursos de rede consomem energia significativa durante as operações de transferência de dados. Para otimizar a comunicação de rede, use as seguintes técnicas:
- Minimizar o tamanho do payload: crie suas APIs e aplicativos para transferir apenas os dados necessários para uma solicitação. Evite buscar ou retornar grandes estruturas JSON ou XML nos casos em que apenas alguns campos são necessários. Verifique se as estruturas de dados retornadas são concisas.
- Reduzir viagens de ida e volta: para reduzir o número de viagens de ida e volta de rede que são necessárias para concluir uma ação do usuário, use protocolos mais inteligentes. Por exemplo, prefira HTTP/3 em vez de HTTP/1.1, escolha GraphQL em vez de REST, use protocolos binários e consolide chamadas de API. Ao reduzir o volume de chamadas de rede, você reduz o consumo de energia dos servidores e dos dispositivos do usuário final.
Implementar a otimização de front-end
A otimização de front-end minimiza os dados que os usuários finais precisam baixar e processar, o que ajuda a reduzir a carga nos recursos dos dispositivos do usuário final.
Minimizar código e recursos
Quando os usuários finais precisam baixar e processar recursos menores e mais eficientemente estruturados, os dispositivos consomem menos energia. Para minimizar o volume de download e a carga de processamento nos dispositivos do usuário final, use as seguintes técnicas:
- Minimização e compactação: para arquivos JavaScript, CSS e HTML, remova caracteres desnecessários, como espaços em branco e comentários, usando ferramentas de minimização adequadas. Verifique se arquivos como imagens estão compactados e otimizados. É possível automatizar a minimização e a compactação de recursos da Web usando um pipeline de CI/CD.
- Carregamento lento: carregue imagens, vídeos e recursos não críticos apenas quando eles forem realmente necessários, como quando esses elementos são rolados para a janela de visualização de uma página da Web. Essa abordagem reduz o volume de transferência de dados inicial e a carga de processamento nos dispositivos do usuário final.
- Pacotes JavaScript menores: elimine o código não utilizado dos pacotes JavaScript usando bundlers de módulos modernos e técnicas como o tree shaking. Essa abordagem resulta em arquivos menores que são carregados mais rapidamente e usam menos recursos do servidor.
- Armazenamento em cache do navegador: use cabeçalhos de armazenamento em cache HTTP para instruir o navegador do usuário a armazenar recursos estáticos localmente. O processo de cache do navegador ajuda a evitar downloads repetidos e tráfego de rede desnecessário em visitas subsequentes.
Priorizar a experiência do usuário (UX) leve
O design da interface do usuário pode ter um impacto significativo na complexidade computacional para renderizar o conteúdo do front-end. Para criar interfaces de front-end que ofereçam uma UX leve, use as seguintes técnicas:
- Renderização eficiente: evite a manipulação frequente e com uso intensivo de recursos do Modelo de objeto de documentos (DOM, na sigla em inglês). Escreva um código que minimize a complexidade de renderização e elimine a nova renderização desnecessária.
- Padrões de design leves: quando apropriado, prefira sites estáticos ou Progressive Web Apps (PWAs). Esses sites e apps são carregados mais rapidamente e exigem menos recursos do servidor.
- Acessibilidade e performance: sites responsivos e de carregamento rápido costumam ser mais sustentáveis e acessíveis. Um design otimizado e sem poluição visual reduz os recursos consumidos quando o conteúdo é renderizado. Sites otimizados para performance e velocidade podem ajudar a gerar mais receita. De acordo com um estudo de pesquisa da Deloitte e do Google, Milliseconds Make Millions, uma melhoria de 0,1 segundo (100 ms) na velocidade do site leva a um aumento de 8,4% nas conversões de sites de varejo e um aumento de 9,2% no valor médio do pedido.