Os desenvolvedores são animais estranhos; usaremos uma ferramenta ou biblioteca totalmente nova em um aplicativo sem pensar muito, mas seremos cautelosos ao implantá-la na produção. Ninguém quer que seu pager comece a zumbir no meio da noite, sem mencionar a pressão para manter os aplicativos rodando com 9s de confiabilidade. Os desenvolvedores são aventureiros na construção e codificação de aplicativos, mas muito conservadores nos elementos operacionais.
Insira um fenômeno chamado superprovisionamento: adicionar potência extra (normalmente CPU e RAM) à implantação de um aplicativo em um ambiente de nuvem para garantir que o aplicativo tenha espaço suficiente para inicialização e para picos que ocorrem durante a execução do aplicativo.
Felizmente, existem maneiras de reduzir a necessidade de provisionamento excessivo, economizando assim uma quantidade significativa de gastos com nuvem. Examinarei especificamente o superprovisionamento no contexto de aplicativos Java.
A carga do aplicativo nunca é estável
Como qualquer desenvolvedor ou pessoa de DevOps lhe dirá, o tráfego para um aplicativo quase nunca é uniforme ao longo do dia ou da semana, e a grande maioria dos aplicativos tem carga irregular ao longo do tempo. Cada aplicativo tem pontos baixos onde não atende muitas solicitações de usuários ou processa dados, e picos onde a utilização do aplicativo é extremamente alta. Esses picos são adequados, desde que as instâncias do aplicativo não sejam levadas ao ponto em que o aplicativo apresente problemas como:
Latência excepcionalmente longa nas respostas e não cumprimento dos acordos de nível de serviço (SLAs).
A utilização excessiva de memória leva à destruição do coletor de lixo (GC) na Java Virtual Machine (JVM).
A falta de recursos (thread da CPU, identificadores de arquivo/rede) leva à rejeição de solicitações recebidas e à incapacidade de processamento.
Os dois últimos problemas podem fazer com que o aplicativo pare completamente de responder e pareça que não está realizando nenhum processamento. Durante os testes, os desenvolvedores observam esse limite superior e dimensionam o número de núcleos de CPU e memória necessários. Em seguida, eles adicionam uma quantidade muitas vezes arbitrária de CPU e memória para acomodar picos — superprovisionando os recursos disponíveis do aplicativo. O superprovisionamento é a rede de segurança da equipe de desenvolvimento para garantir que tudo funcione bem e que os usuários estejam satisfeitos com o tempo de resposta.
No entanto, o provisionamento excessivo adiciona um custo significativo à execução de um aplicativo. Uma VM em nuvem em execução normalmente tem CPU fixa (núcleo ou CPU virtual) e memória e não é considerada elástica. Isso significa que você está pagando pela capacidade configurada, esteja você utilizando-a totalmente ou não. Esse espaço extra pode variar de 5% a 50% de sua computação em nuvem provisionada, dependendo de quanta capacidade extra a equipe de desenvolvimento considera necessária para acomodar o pico.
Para ajudá-lo a lidar com o provisionamento excessivo e economizar dinheiro em gastos com nuvem, você pode usar determinadas estratégias, dependendo se estiver fazendo escalonamento vertical ou horizontal. Descreverei esses dois modelos de escalonamento junto com estratégias para cada um. Essas estratégias e técnicas podem ser usadas quer você esteja executando na nuvem ou no local.
Escala vertical
O dimensionamento vertical é a estratégia mais simples para dimensionar um aplicativo para lidar com mais carga, mas é menos flexível que o dimensionamento horizontal. O escalonamento vertical significa adicionar mais núcleos de CPU e mais memória a um aplicativo em um servidor físico ou virtual (ou adicionar mais armazenamento SSD mais rápido ou mais, se seu aplicativo usar muita E/S). Alterar essas coisas requer parar e reiniciar um aplicativo, o que é prejudicial. Mas existe uma maneira de reduzir o provisionamento excessivo para esse tipo de escalonamento.
Melhores testes e estimativas de carga
O teste de desempenho é considerado o tipo de teste mais difícil – requer profundo conhecimento do inteiro aplicativo e todos os serviços conectados. Configurar um ambiente de teste de desempenho exige muito trabalho e mantê-lo atualizado com as características do ambiente de produção também é um desafio. Gerar carga que imite a produção juntamente com dados de aplicação (tanto o tamanho quanto a forma dos dados de produção) requer reflexão e esforço para acertar.
Por causa disso, as equipes de desenvolvimento costumam fazer algumas suposições e tomar alguns atalhos. Isso é bom, mas leva à superestimação e superprovisionamento do tamanho das instâncias de produção do aplicativo.
O que os desenvolvedores podem fazer para obter dados de melhor desempenho para dimensionar corretamente seus aplicativos Java? Aqui estão as três principais coisas que você pode fazer para determinar os requisitos de capacidade máxima do seu aplicativo.
1. Meça a utilização de CPU e memória para o servidor e a JVM
Freqüentemente, os desenvolvedores analisam apenas a CPU e a utilização da memória do servidor (ou VM) para determinar a quantidade necessária de ambos para lidar com picos de carga. Usar ferramentas que monitoram essas coisas dentro da JVM ajudará a colocá-las no nível certo:
Monitoramento JVM GC: Isso pode ajudar a detectar pouca memória, o que leva a uma alta utilização da CPU à medida que a JVM entra em cenários de lixo do GC. Isso também pode ajudar a detectar onde muita memória está alocada, causando longas pausas no GC, o que causa latência maior do que o esperado. Reduzir a memória desnecessária também pode economizar dinheiro.
Monitoramento de thread JVM: Isso pode ajudar a detectar quando você não tem CPU suficiente, o que leva a longos tempos de resposta ou falta de resposta. Isso pode ajudar a detectar muitos threads ociosos e, ao reduzir o número de núcleos alocados, você também pode economizar dinheiro.
2. Novas versões de JVM oferecem melhor desempenho do que versões mais antigas
Em nossos testes do JDK 11 ao 17 ao 21, vemos melhorias no uso da CPU a cada versão da JVM. É claro que o código da sua aplicação pode precisar de alguns ajustes, especialmente se a sua aplicação for baseada em uma versão anterior ao Java 11.
Existem também diferentes algoritmos de GC que permitem obter mais eficiência de sua VM na nuvem; no entanto, isso depende muito da utilização de memória do seu aplicativo. Por exemplo, um aplicativo que faz processamento e transformação pesados de dados terá um perfil de GC diferente daquele que é um aplicativo RESTful. Você pode conferir a seção GC do blog da Azul para mais informações.
3. Entenda como funciona a JVM
O diagrama abaixo mostra como um aplicativo Java típico é executado, desde a inicialização da JVM até como ele é executado ao longo do tempo. O uso da CPU é alto na inicialização; esta é a inicialização da JVM, carregamento de classes, etc. Em seguida, a estrutura do seu aplicativo (por exemplo, Spring Boot) inicia, inicializa e atinge um estado “pronto para atender solicitações”.
Observe a linha acima do pico que mostra o quanto a CPU está superprovisionada para a implantação de VM deste aplicativo (uma rede de segurança para altas cargas em rajadas). À medida que o compilador just-in-time (JIT) da JVM otimiza os caminhos do código, o aplicativo obtém mais eficiente – usa menos CPU para atender a mesma quantidade de carga. O que acaba acontecendo é que, além do espaço extra que você dá ao aplicativo, a JVM atinge uma linha de base de utilização de CPU mais baixa devido às otimizações do compilador JIT. Conseqüentemente, a quantidade de superprovisionamento aumenta! Isso significa que agora você tem ainda mais desperdício de CPU alocada — e uma chance de economizar mais dinheiro.
Usar uma JVM de alto desempenho significa que você pode reduzir (ou remover completamente) o superprovisionamento. Compreender essa curva e como ela afeta seu aplicativo pode ajudar a reduzir a rede de segurança alocada para a instância de VM do seu aplicativo. Se você conseguir reduzir a linha superior (“superprovisionado”) depois de saber onde estará o pico de cauda longa, você será capaz de alocar menos núcleos de CPU e economizar em gastos com nuvem.
Escala horizontal
A computação elástica tem sido considerada o Santo Graal do desenvolvimento de aplicativos escaláveis há muitos anos, e a escalabilidade horizontal é a base da computação elástica. O dimensionamento horizontal significa adicionar capacidade a um aplicativo adicionando mais servidores (que possuem sua própria CPU e memória), em vez de adicionar mais núcleos de CPU e memória a um servidor existente.
No entanto, o dimensionamento horizontal é mais complexo e requer mais planejamento e configuração mais externa (para o aplicativo) do que o dimensionamento vertical. E é menos eficiente que o escalonamento vertical, pois é necessário introduzir uma camada de roteamento, o que significa mais processamento e sobrecarga de rede.
A redução do provisionamento excessivo em uma implantação de escalabilidade horizontal de um aplicativo Java é feita adicionando e removendo capacidade conforme necessário, geralmente de uma forma automatizada que detecta a carga e aumenta ou diminui as instâncias do nó do aplicativo. Conseqüentemente, você terá alguma capacidade superprovisionada, mas uma pequena quantidade, por um pequeno período de tempo (dependendo de como você a configurou).
Reduza o tamanho do seu aplicativo
À medida que passamos da arquitetura de aplicativos como monólitos para microsserviços (e funções de nuvem ainda menores), tornamos os aplicativos cada vez menores. Há benefícios e compensações para essas diferentes arquiteturas, mas no contexto de otimizações de custos de nuvem para aplicativos, usar especificamente o dimensionamento horizontal para obter uma computação elástica menor (ou de pequeno a médio porte) é o melhor.
Reduzir o tamanho do aplicativo reduz a quantidade de CPU e memória que você precisa alocar para cada instância do seu aplicativo. Isso permite um dimensionamento mais incremental e um uso mais eficiente dos recursos, o que, por sua vez, significa um controle mais refinado sobre os custos da nuvem. Quanto menor a unidade de implantação, mais (ou menos) você paga à medida que aumenta e diminui. É claro que isso só é possível se você estiver usando o escalonamento automático.
Usar escalonamento automático
O escalonamento automático refere-se à capacidade de um aplicativo de adicionar ou remover nós de instância de aplicativo conforme a carga aumenta ou diminui. Com a otimização dos custos da nuvem, estamos interessados em escalar de forma mais agressiva abaixoou parando nós de instância do aplicativo. Dependendo do ambiente usado para criar seu cluster de aplicativos, você terá diferentes opções de escalonamento automático. A plataforma de escalonamento automático mais popular é o Kubernetes, que oferece suporte ao escalonamento automático. A principal desvantagem do Kubernetes é que ele introduz um alto nível de complexidade nas implantações padrão de cluster distribuído fixo.
A alternativa mais simples ao Kubernetes são os Containers as a Service (CaaS), como AWS Fargate, Google Cloud Run ou Microsoft Azure Containers. Esses serviços de implantação oferecem uma maneira muito mais fácil de implantar seu aplicativo. Você entrega seu aplicativo, em um contêiner Docker, ao serviço e ele lida com o escalonamento automático para cima e para baixo. A desvantagem das soluções CaaS é que elas custam mais do que VMs padrão e possivelmente mais do que uma implantação gerenciada do Kubernetes.
Conclusão
A redução do provisionamento excessivo pode ajudar você a economizar nos custos da nuvem. Em última análise, o que você pode implementar depende muito do seu aplicativo e de seu perfil de desempenho. Compreender o que acontece quando os aplicativos são inicializados e executados é útil independentemente da estratégia usada para reduzir o provisionamento excessivo. Compreender o perfil de CPU e memória de aplicativos Java ajudará você a entender o desempenho de seus aplicativos em tempo de execução.
Considere usar uma JVM de alto desempenho mais eficiente, como o Azul Platform Prime, para implantações de aplicativos Java de pequeno a grande porte. Plataforma Azul Prime:
Lida com picos de carga melhor do que outras JVMs devido ao seu C4 GC avançado, otimizações de baixo nível e compilador Falcon JIT avançado.
Pode evitar o aumento do JIT (e a alta utilização da CPU do JIT) com o ReadyNow.
Fornece menor latência sob carga, além de lidar com picos mais altos devido à forma como lida com a carga de pico.
Para saber mais, baixe o white paper da IDC sobre Otimização do desempenho de aplicativos Java para melhores resultados de negócios e eficiência de custos na nuvem.
YOUTUBE.COM/THENEWSTACK
A tecnologia avança rápido, não perca um episódio. Inscreva-se em nosso canal no YouTube para transmitir todos os nossos podcasts, entrevistas, demonstrações e muito mais.
SE INSCREVER
Pratik Patel é Java Champion e vice-presidente de relações com desenvolvedores da Azul Systems. Ele é um entusiasta de software e hardware com experiência em engenharia de software nos setores de viagens, saúde, telecomunicações, serviços financeiros e startups. Ele escreveu…
Este site utiliza cookies para melhorar sua experiência de navegação. Ao continuar, você concorda com o uso de cookies. Para mais informações, consulte nossa Política de Privacidade.
Funcional
Sempre ativo
O armazenamento ou acesso técnico é estritamente necessário para a finalidade legítima de permitir a utilização de um serviço específico explicitamente solicitado pelo assinante ou utilizador, ou com a finalidade exclusiva de efetuar a transmissão de uma comunicação através de uma rede de comunicações eletrónicas.
Preferências
O armazenamento ou acesso técnico é necessário para o propósito legítimo de armazenar preferências que não são solicitadas pelo assinante ou usuário.
Estatísticas
O armazenamento ou acesso técnico que é usado exclusivamente para fins estatísticos.O armazenamento técnico ou acesso que é usado exclusivamente para fins estatísticos anônimos. Sem uma intimação, conformidade voluntária por parte de seu provedor de serviços de Internet ou registros adicionais de terceiros, as informações armazenadas ou recuperadas apenas para esse fim geralmente não podem ser usadas para identificá-lo.
Marketing
O armazenamento ou acesso técnico é necessário para criar perfis de usuário para enviar publicidade ou para rastrear o usuário em um site ou em vários sites para fins de marketing semelhantes.