Share via


Contentores das suas aplicações Java

Este artigo fornece uma visão geral das estratégias e configurações recomendadas para a conteinerização de aplicativos Java.

Ao colocar um contêiner em um aplicativo Java, considere cuidadosamente quanto tempo de CPU o contêiner terá disponível. Em seguida, considere quanta memória estará disponível em termos de quantidade total de memória e o tamanho do heap da Java Virtual Machine (JVM). Em ambientes em contêineres, os aplicativos podem ter acesso a todos os processadores e, portanto, ser capazes de executar vários threads em paralelo. É comum, no entanto, que os contêineres tenham uma cota de CPU aplicada que pode limitar o acesso às CPUs.

A JVM tem heurística para determinar o número de "processadores disponíveis" com base na cota de CPU, o que pode influenciar drasticamente o desempenho de aplicativos Java. A memória alocada para o próprio contêiner e o tamanho da área de heap para a JVM são tão importantes quanto os processadores. Esses fatores determinarão o comportamento do coletor de lixo (GC) e o desempenho geral do sistema.

Contentorizar uma nova aplicação

Ao colocar em contêiner uma carga de trabalho Java para um novo aplicativo, você precisa levar duas coisas em conta ao pensar em memória:

  • A memória alocada para o próprio contêiner.
  • A quantidade de memória disponível para o processo Java.

Compreender a ergonomia padrão da JVM

Os aplicativos precisam de um ponto de partida e configurações. A JVM tem ergonomia padrão com valores predefinidos que são baseados no número de processadores disponíveis e na quantidade de memória no sistema. Os valores padrão mostrados nas tabelas a seguir são usados quando a JVM é iniciada sem sinalizadores ou parâmetros de inicialização específicos.

A tabela a seguir mostra o GC padrão usado para os recursos disponíveis:

Recursos disponíveis GC padrão
Qualquer número de processadores
Até 1791 MB de memória
SerialGC
2+ processadores
1792 MB ou mais de memória
G1GC

A tabela a seguir mostra o tamanho máximo de heap padrão, dependendo da quantidade de memória disponível no ambiente em que a JVM está sendo executada:

Memória disponível Tamanho máximo de heap padrão
Até 256 MB 50% da memória disponível
256 MB até 512 MB ~127MB
Mais de 512 MB 25% da memória disponível

O tamanho de heap inicial padrão é 1/64 da memória disponível.

Esses valores são válidos para OpenJDK 11 e posterior, e para a maioria das distribuições, incluindo Microsoft Build of OpenJDK, Azul Zulu, Eclipse Temurin, Oracle OpenJDK e outros.

Determinar a memória do contêiner

Escolha uma quantidade de memória de contêiner que atenda melhor à sua carga de trabalho, dependendo das necessidades do seu aplicativo e de seus padrões de uso distintos. Por exemplo, se seu aplicativo cria gráficos de objetos grandes, você provavelmente precisará de mais memória do que precisaria para aplicativos com muitos gráficos de objetos pequenos.

Gorjeta

Se você não sabe quanta memória alocar, um bom ponto de partida é 4 GB.

Determinar a memória de heap da JVM

Ao alocar memória de heap da JVM, lembre-se de que a JVM precisa de mais memória do que apenas o que é usado para a pilha da JVM. Quando você define a memória de heap máxima da JVM, ela nunca deve ser igual à quantidade de memória do contêiner, pois isso causará erros de falta de memória (OOM) do contêiner e falhas no contêiner.

Gorjeta

Aloque 75% da memória do contêiner para o heap da JVM.

No OpenJDK 11 e posterior, você pode definir o tamanho do heap da JVM das seguintes maneiras:

Description Sinalizador Exemplos
Valor fixo -Xmx -Xmx4g
Valor dinâmico -XX:MaxRAMPercentage -XX:MaxRAMPercentage=75

Tamanho mínimo/inicial da pilha

Onde o ambiente tem a garantia de ter uma certa quantidade de memória reservada para uma instância da JVM, como em um contêiner, você deve definir o tamanho mínimo de heap - ou tamanho de heap inicial - para o mesmo tamanho que o tamanho máximo de heap. Essa configuração indica à JVM que ela não deve executar a tarefa de liberar memória para o sistema operacional.

Para definir um tamanho mínimo de heap, use -Xms para quantidades absolutas ou -XX:InitialRAMPercentage para quantias percentuais.

Importante

A bandeira-XX:MinRAMPercentage, apesar do que o nome sugere, é usada para definir a porcentagem máxima de RAM padrão para sistemas com até 256 MB de RAM disponível no sistema.

Chart showing the default heap size on OpenJDK 17.

Determinar qual GC usar

Anteriormente, você determinava a quantidade de memória de heap da JVM para começar. O próximo passo é escolher o seu GC. A quantidade máxima de memória de heap da JVM que você tem geralmente é um fator na escolha do GC. A tabela a seguir descreve as características de cada GC.

Fatores SerialGC ParallelGC G1GC ZGC ShenandoahGC
Número de núcleos 1 2 2 2 2
Multi-threaded Não Sim Sim Sim Sim
Tamanho da pilha Java <4 GBytes <4 GBytes >4 GBytes >4 GBytes >4 GBytes
Colocar em pausa Sim Sim Sim Sim (<1 ms) Sim (<10 ms)
Tolerância Mínimo Mínimo Moderado Moderado Moderado
Efeito de latência de cauda Máximo Máximo Máximo Mínimo Moderado
Versão JDK Todos Todos JDK 8+ JDK 17+ JDK 11+
Melhor para Pilhas pequenas de núcleo único Pilhas pequenas com vários núcleos ou cargas de trabalho em lote com qualquer tamanho de heap Responsivo em pilhas médias a grandes (interações solicitação-resposta/banco de dados) Responsivo em pilhas médias a grandes (interações solicitação-resposta/banco de dados) Responsivo em pilhas médias a grandes (interações solicitação-resposta/banco de dados)

Gorjeta

Para a maioria dos aplicativos de microsserviço de uso geral, comece com o GC paralelo.

Determinar quantos núcleos de CPU são necessários

Para qualquer GC diferente do SerialGC, recomendamos dois ou mais núcleos vCPU - ou pelo menos 2000mcpu_limit no Kubernetes. Não recomendamos selecionar nada menos que 1 núcleo de vCPU em ambientes em contêineres.

Gorjeta

Se você não sabe com quantos núcleos começar, uma boa escolha é 2 núcleos vCPU.

Escolha um ponto de partida

Recomendamos começar com duas réplicas ou instâncias em ambientes de orquestração de contêineres, como Kubernetes, OpenShift, Azure Spring Apps, Azure Container Apps e Azure App Service. A tabela a seguir resume os pontos de partida recomendados para a conteinerização de seu novo aplicativo Java.

Núcleos vCPU Memória do contentor Tamanho da pilha da JVM GC Réplicas
2 4 GB 75% ParallelGC 2

Os parâmetros da JVM a serem usados são: -XX:+UseParallelGC -XX:MaxRAMPercentage=75

Contentorizar uma aplicação existente (no local)

Se seu aplicativo já estiver sendo executado no local ou em uma VM na nuvem, recomendamos que você comece com:

  • A mesma quantidade de memória que o aplicativo tem acesso atualmente.
  • O mesmo número de CPUs (núcleos vCPU) que o aplicativo tem disponível atualmente.
  • Os mesmos parâmetros da JVM que você usa atualmente.

Se os núcleos de vCPU e/ou a combinação de memória de contêiner não estiverem disponíveis, escolha o mais próximo, arredondando os núcleos de vCPU e a memória de contêiner.

Próximos passos

Agora que você entende as recomendações gerais para a conteinerização de aplicativos Java, continue para o seguinte artigo para estabelecer uma linha de base de conteinerização: