Java-buildpack: Impossível executar aplicativos Spring Boot com configuração padrão e <512M

Criado em 31 dez. 2018  ·  8Comentários  ·  Fonte: cloudfoundry/java-buildpack

O fato de não ser possível executar um Spring Boot hello world (MVC ou WebFlux) com menos de 512M e que a maioria dos aplicativos não triviais requer pelo menos 1G no Cloud Foundry é muito frustrante para os usuários e dá a falsa impressão de que Spring O boot não pode ser executado com menos de 1G de memória.

Estamos trabalhando com @dsyer , equipe de inicialização e outros para otimizar Spring Framework e Spring Boot para gerar menos pressão de GC e ter menor consumo de memória, mas acho que também poderíamos melhorar o Cloud Foundry para lidar com isso de uma maneira melhor.

Levantei https://github.com/cloudfoundry/java-buildpack-memory-calculator/issues/24 sobre a regra de cálculo de memória.

Outro ponto: se o número da classe é calculado contando todos os .class arquivos no aplicativo, incluindo suas dependências, não é uma fonte confiável de informações para aplicativos Spring que não tem uma granularidade JAR muito fina e irá carregar efetivamente apenas uma pequena proporção das classes disponíveis em Spring JARs.

O problema é ainda mais visível com as otimizações que lançamos no Spring Boot 2.1 e a otimização em que estamos trabalhando atualmente para o Spring Boot 2.2.

Minha intuição é que os usuários típicos sabem quanto Xmx memória é necessária localmente por seu aplicativo, e talvez devêssemos usar essa informação por padrão.

question

Comentários muito úteis

É possível operar com menos de 512M configurando a calculadora de memória.
O seguinte manifesto funciona para mim (spring boot + webflux).

applications:
- name: myapp
  path: target/myapp-0.0.1-SNAPSHOT.jar
  memory: 256m
  env:
    JAVA_OPTS: '-XX:ReservedCodeCacheSize=32M -XX:MaxDirectMemorySize=32M'
    JBP_CONFIG_OPEN_JDK_JRE: '[memory_calculator: {stack_threads: 30}, jre: {version: 11.+}]'

Um aplicativo vanilla webflux roda com apenas

Sou um grande fã da calculadora de memória, pois a maioria dos desenvolvedores tende a se preocupar apenas com o tamanho do heap e obter um OOME inesperado (por exemplo, Metaspace), mas concordo que podemos melhorá-lo.
O tamanho de thread padrão (300?) Na calculadora seria muito grande para pelo menos webflux.

Para iniciantes, é muito difícil encontrar uma maneira de personalizar o tamanho da memória.
Os exemplos de configuração por caso de uso no README seriam muito úteis.

Todos 8 comentários

É possível operar com menos de 512M configurando a calculadora de memória.
O seguinte manifesto funciona para mim (spring boot + webflux).

applications:
- name: myapp
  path: target/myapp-0.0.1-SNAPSHOT.jar
  memory: 256m
  env:
    JAVA_OPTS: '-XX:ReservedCodeCacheSize=32M -XX:MaxDirectMemorySize=32M'
    JBP_CONFIG_OPEN_JDK_JRE: '[memory_calculator: {stack_threads: 30}, jre: {version: 11.+}]'

Um aplicativo vanilla webflux roda com apenas

Sou um grande fã da calculadora de memória, pois a maioria dos desenvolvedores tende a se preocupar apenas com o tamanho do heap e obter um OOME inesperado (por exemplo, Metaspace), mas concordo que podemos melhorá-lo.
O tamanho de thread padrão (300?) Na calculadora seria muito grande para pelo menos webflux.

Para iniciantes, é muito difícil encontrar uma maneira de personalizar o tamanho da memória.
Os exemplos de configuração por caso de uso no README seriam muito úteis.

@making Eu atualizei o título deste problema para deixar mais claro que se trata de uma configuração padrão

O número de threads que você menciona para o aplicativo WebFlux é realmente um ponto muito interessante, o pacote de construção pode fornecer valor agregado adicional ao detectar que tipo de aplicativo é. Pode ser complicado, pois alguns aplicativos MVC podem usar Reativo WebClient , mas tenho certeza de que podemos fazer algo mais inteligente e preciso.

Sua configuração de memória personalizada destaca IMO que algo está errado no mecanismo de configuração automática. Conforme explicado em https://github.com/cloudfoundry/java-buildpack-memory-calculator/issues/24 , se eu especificar explicitamente o número de classes (entre 8.000 e 10.000) efetivamente usadas pelos aplicativos de inicialização, o parâmetro gerado é -XX:ReservedCodeCacheSize=240M , onde você especifica -XX:ReservedCodeCacheSize=32M . Essa diferença é realmente enorme, poderíamos dar um palpite mais fundamentado?

Além disso, 8.000 ou 10.000 são o número de classes efetivamente usadas por aplicativos de inicialização. Se o pacote de compilação está computando isso a partir do número de classes no aplicativo + dependências, tendo a pensar que o número de classes especificadas para a calculadora de memória será artificialmente alto (ainda preciso verificar o valor adivinhado atualmente, mas o pacote de compilação) devido à natureza dos JARs do Spring Framework.

Também estou querendo saber se aproveitamos as novas opções de memória de contêiner disponíveis no Java 8 e no Java 11. mais recentes. Eles são projetados para Docker, mas acho que também poderíamos nos beneficiar disso no Cloud Foundry. O Java runtime está ciente de que estamos executando em contêineres, apesar do CF não usar o Docker? Aproveitamos opções como -XX:InitialRAMPercentage , -XX:MaxRAMPercentage ou -XX:MinRAMPercentage ?

É um problema complicado @sdeleuze. O java-buildpack usa padrões de java, que presumimos que algum pensamento foi feito na configuração de java, permitindo que os aplicativos funcionem, por padrão, mais como quando não são executados em CF? Ou o java-buildpack altera os padrões para tornar a experiência inicial melhor, mas deixa os usuários procurando por respostas quando o aplicativo não é executado conforme o esperado, não no CF?

Hoje, o java-buildpack optou por usar os padrões java e tomcat, confiando nesses valores como um aplicativo típico hoje. Pessoalmente, gosto dessa abordagem mais do que alterar os padrões de java que podem afetar o aplicativo de maneiras não muito visíveis / explícitas para o usuário.

No que diz respeito às novas propriedades, meu entendimento das propriedades RAMPercentage é que elas simplesmente definem valores de heap automaticamente com base em uma porcentagem de memória RAM disponível. Sem pensar nos requisitos de memória não heap, como tamanho do cache de código, tamanho da pilha de encadeamentos, metaspace, sobrecarga de memória GC, etc. Esse trabalho ainda é deixado como um exercício para o usuário adivinhar quanta memória não heap seu aplicativo precisa. Estou ansioso por um dia em que java possa simplesmente gerenciar todos os pools de memória adequadamente para manter um aplicativo dentro das restrições de memória de um contêiner. Mas suspeito que ainda estamos muito longe disso.

Como uma observação lateral, esta é a configuração JAVA_OPTS e jre que defini para meus aplicativos que preciso para ser estável com pouca memória e velocidade não é um fator.

  • Eu defino MaxMetaSize como descoberto por meio de criação de perfil.
    JAVA_OPTS
-Xss256K -Xms1M -XX:+UseSerialGC -Djava.compiler=none -XX:ReservedCodeCacheSize=2496k -XX:MaxDirectMemorySize=1M

configuração jre

  stack_threads: 20
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

chrylis picture chrylis  ·  10Comentários

ghost picture ghost  ·  26Comentários

edeandrea picture edeandrea  ·  4Comentários

mkuratczyk picture mkuratczyk  ·  10Comentários

samzilverberg picture samzilverberg  ·  13Comentários