Crie aplicativos de microsserviços com base em compilação estática

Autor: Rao Zihao (Cheng Pu)

Limitações do Java

Um aplicativo Java tradicional pode ser dividido nas seguintes etapas, desde a escrita do código até a inicialização e operação:

  1. Primeiro, escreva o programa de código-fonte .java.
  2. Em seguida, use a ferramenta javac para traduzir o arquivo .java em bytecode .class. Bytecode é um dos conteúdos mais importantes em Java. É precisamente por causa de sua aparência que Java realiza a blindagem do ambiente subjacente e atinge Write once , o efeito de correr em qualquer lugar!
  3. O arquivo .class baseado na etapa 2 será empacotado em um pacote jar ou pacote war para implantação e execução.Durante o processo de implantação, o aplicativo é carregado por meio da máquina virtual Java e, em seguida, o bytecode é interpretado para executar a lógica de negócios.

Todo o processo é mostrado na figura abaixo:

foto

Figura 1: Processo de execução do programa Java

O processo acima não traz apenas vantagens aos programas Java que outras linguagens de programação não possuem, como plataforma cruzada, facilidade de uso, etc. Mas também traz alguns problemas de desempenho para programas Java, como velocidade de inicialização lenta e alto uso de memória durante a execução.

Problema de partida a frio

O processo detalhado de inicialização e execução do programa Java na Figura 1 é mostrado na Figura 2 abaixo:

foto

*Figura 2: Análise do processo de inicialização do programa Java [ 1] *

O processo de inicialização de um aplicativo Java requer primeiro o carregamento do programa de software da máquina virtual JVM correspondente ao aplicativo na memória, conforme mostrado na parte vermelha da figura acima. Em seguida, a máquina virtual JVM carrega o programa aplicativo correspondente na memória, este processo corresponde à parte de carregamento de classe azul claro (Class Load, CL) na figura acima. Durante o processo de carregamento da classe, o programa aplicativo começará a ser interpretado e executado, correspondendo à parte verde clara da figura acima. Explique que a JVM recicla objetos inúteis durante o processo de execução, o que corresponde à parte amarela na figura acima. À medida que o programa avança, a JVM usará a tecnologia Just In Time (JIT) para compilar e otimizar códigos que são executados com mais frequência, a fim de melhorar a velocidade de execução do aplicativo. O processo JIT corresponde à parte branca da figura acima. O código após compilação e otimização JIT corresponde à parte verde escura da figura.

Após a análise acima, não é difícil ver que um programa Java passará por vários estágios de VM init, App init e App ativo desde a inicialização até ser compilado dinamicamente e otimizado pelo JIT. Comparado com algumas outras linguagens compiladas, seu início a frio problema é mais sério.

Problema de alto uso de memória durante o tempo de execução

Além do problema de inicialização a frio, não é difícil ver pela análise acima que quando um programa Java está em execução, ele primeiro precisa carregar uma máquina virtual JVM sem fazer nada. Esta operação geralmente ocupa uma certa quantidade de memória. Além disso, porque o programa Java primeiro interpreta e executa o bytecode e, em seguida, executa a compilação e otimização JIT.

Como em comparação com algumas linguagens compiladas, as ações de compilação e otimização são adiadas para o tempo de execução, é muito fácil carregar muito mais código do que o código que realmente precisa ser executado, resultando em algum uso de memória inválido. Resumindo, essas são as principais razões pelas quais muitas pessoas criticam frequentemente o alto uso de memória dos programas Java.

Programas Java mais leves

tecnologia de compilação estática

Como o método tradicional de execução de programas Java que primeiro interpreta e executa e depois compila dinamicamente tem muitos dos problemas acima, existe alguma maneira de fazer programas Java, como outras linguagens de programação, como C/C++, compilarem primeiro e depois executarem para resolver? os problemas acima?

A resposta é sim. Compilação Ahead-of-Time (Compilação AOT) ou compilação estática foi proposta no campo Java muito cedo. A ideia central é avançar a fase de compilação dos programas Java antes da inicialização do programa e, em seguida, realizar a compilação e otimização do código durante a fase de compilação para maximizar a inicialização do programa, eliminar inicializações a frio e reduzir a sobrecarga de memória em tempo de execução.

Existem muitas tecnologias de implementação para compilação estática no campo Java, a mais representativa das quais é a plataforma de tempo de execução multilíngue de código aberto e alto desempenho GraalVM lançada pela Oracle [ 2 ] . Alguns leitores que virem isso podem perguntar: "O que é uma plataforma de tempo de execução multilíngue de alto desempenho? O que isso tem a ver com a compilação estática em si?".

foto

Figura 3: Plataforma de tempo de execução multilíngue GraalVM

Conforme mostrado na Figura 3 acima, GraalVM fornece uma estrutura de implementação de interpretador Truffle, permitindo que os desenvolvedores usem a API fornecida pelo Truffle para implementar rapidamente um interpretador para uma linguagem específica, de modo que programas escritos em várias linguagens de programação na figura acima pode ser compilado.O efeito de execução, tornando-se assim uma plataforma de tempo de execução multilíngue. O compilador do GraalVM que implementa recursos de compilação estática é o GraalVM JIT Compiler. A estrutura de compilação estática e o tempo de execução são implementados pelo subprojeto Substrate VM e são compatíveis com a implementação do tempo de execução OpenJDK.Ele fornece tratamento de exceções, agendamento síncrono, gerenciamento de threads, gerenciamento de memória e outras funções quando o programa de espelho nativo está em execução.

Portanto, GraalVM pode não apenas servir como uma plataforma de tempo de execução poliglota, mas também pode ser usado para compilar programas Java estaticamente, graças ao compilador estático GraalVM JIT Compiler fornecido nele.

Depois de falar sobre a relação entre compilação estática e GraalVM, alguns leitores podem ficar curiosos, quais são as diferenças entre compilação estática baseada em GraalVM e métodos convencionais de interpretação e execução de JVM? Em comparação com o programa Java compilado em tempo de execução JVM atualmente amplamente usado, a diferença entre a gravação de código e a compilação e execução de programas Java com base na compilação estática é mostrada na Figura 4 abaixo:

foto

Figura 4: Comparação entre compilação estática e processo de execução JVM tradicional

Em comparação com o método de tempo de execução JVM, a compilação estática primeiro analisará e compilará o programa antes de executá-lo e, em seguida, gerará um arquivo executável de imagem nativa que está intimamente relacionado ao ambiente de tempo de execução.Finalmente, execute o arquivo diretamente para iniciar o programa para execução.

Neste ponto, alguns leitores podem estar curiosos: o que exatamente o processo de compilação estática na Figura 4 acima fará com o programa Java? Como resolver o problema de coleta de lixo de programas executáveis ​​compilados estaticamente? Conforme mostrado na Figura 5 abaixo, ela descreve o conteúdo de entrada e saída do processo de compilação na implementação da tecnologia de compilação estática GraalVM.

foto

Figura 5: Entrada e saída de compilação estática

Os três primeiros conteúdos de entrada à esquerda na Figura 5: Aplicativo, Bibliotecas e JDK são as três partes necessárias para compilar e executar um programa Java. Substrate VM é a parte central do GraalVM que implementa compilação estática e desempenha um papel importante em todo o processo de compilação estática.

Durante o processo de análise estática, conforme desenhado na parte central da Figura 5 acima, o Substrate VM realiza análise estática no aplicativo por meio de Points-to Analysis insensível ao contexto, que pode realizar análise estática no aplicativo sem executar o programa. análise do programa fonte, uma lista de todas as funções possíveis acessíveis é fornecida e então usada como entrada para o estágio de compilação subsequente para compilar estaticamente o programa. Devido às limitações da análise estática, este processo não pode cobrir recursos dinâmicos como reflexão, proxy dinâmico e chamadas JNI em Java. Isso também fez com que muitas estruturas Java usassem um grande número dos recursos acima no processo de implementação. Portanto, é difícil concluir a análise estática de todos os seus próprios códigos diretamente com base no Substrate VM. Configuração externa adicional [3] é necessária para resolver a análise estática ... suas próprias deficiências.

Por exemplo, a comunidade Spring desenvolveu o AOT Engine [ 4] conforme mostrado na Figura 6 abaixo para ajudar a resolver o problema. O projeto Spring realiza análises estáticas de reflexão, proxy dinâmico e outros conteúdos e os converte em conteúdo que pode ser reconhecido pelo Substrate VM durante a fase de compilação, garantindo que os aplicativos Spring possam ser compilados estaticamente com sucesso com base no Substrate VM.

foto

Figura 6: Motor Spring AOT

Após a conclusão da análise estática, com base na lista de funções acessíveis dos resultados da análise estática, o compilador GraalVM JIT no GraalVM apresentado acima é chamado para compilar o aplicativo em código local que está fortemente relacionado à plataforma de destino para concluir o processo de compilação.

Após a conclusão da compilação, ele entrará no estágio de geração de arquivo executável nativo no lado direito da Figura 5 acima. Durante esse processo, o Substrate VM salvará o conteúdo determinado e inicializado na fase de compilação estática, bem como os dados do tempo de execução do Substrate VM e da biblioteca JDK, no Image Heap do arquivo executável final. O tempo de execução do Substrate VM fornece o arquivo executável final com coleta de lixo, tratamento de exceções e outros recursos necessários durante a operação. Para coleta de lixo, apenas o Serial GC foi fornecido na versão inicial do GraalVM Community Edition. O G1 GC mais capaz é fornecido na Enterprise Edition. No entanto, na versão mais recente da comunidade, a equipe GraalVM também introduziu o G1 GC [ 5] para fornecer aos desenvolvedores recursos de compilação estática mais poderosos.

Adapte-se à compilação estática do GraalVM

Na seção anterior, após apresentar brevemente a tecnologia de compilação estática e suas próprias limitações, muitos desenvolvedores da comunidade externa podem se perguntar neste momento: como um projeto de código aberto Java pode realizar rapidamente a adaptação da compilação estática? Para este problema, de fato, o problema central e essencial a ser resolvido é converter conteúdo dinâmico que não pode ser reconhecido e processado pelo GraalVM na estrutura de código aberto em conteúdo identificável. Portanto, como este problema é diferente em diferentes frameworks, a solução também terá algumas diferenças. Por exemplo, no Spring, o AOT Engine desenvolvido para seu próprio framework pode resolver o problema de que o processo de inicialização das classes registradas fornecidas por seu framework por meio da anotação @Configuration não pode ser reconhecido no estágio de compilação estática, e gerar agentes dinâmicos na compilação estática estágio de antecedência que é originalmente gerado durante o estágio de execução.Esta classe resolve o problema de que classes de proxy de compilação estática direta não podem ser geradas de forma eficaz [ 6] para obter adaptação de compilação estática de aplicativos Spring.

Para muitos frameworks de código aberto implementados com base em Spring, se as características dinâmicas que não podem ser reconhecidas pelo GraalVM são causadas pelo uso do padrão Spring, por pertencerem ao sistema Spring, o processo de compilação estática certamente exigirá a participação do Spring AOT Engine Portanto, o framework em si não precisa fornecer nenhuma adaptação para ter capacidades de compilação estática.

Para projetos de sistema não Spring ou se você usar alguma reflexão nativa ou outros recursos dinâmicos Java no JDK, será necessário fornecer o arquivo de configuração estática correspondente no projeto para o uso dinâmico de Java em seu próprio código para que o compilador possa identificar durante o processo de compilação estática.As características dinâmicas do projeto devem ser compiladas e construídas para obter uma compilação e execução suaves do projeto. Em resposta a esta situação, GraalVM fornece um Agente de Rastreamento chamado agente de imagem nativa para ajudá-lo a coletar metadados e preparar arquivos de configuração de forma mais conveniente. O Agente coleta automaticamente o uso de recursos dinâmicos de aplicativos executados em Java VMs regulares e os converte em arquivos de configuração que o GraalVM pode reconhecer. Por fim, armazene o arquivo de configuração dinâmica do próprio framework gerado pelo Agent no diretório META-INF/native-image/<group.id>/<artifact.id> do projeto, e você poderá usar essas configurações durante o processo de compilação estática. Conteúdo, identificando recursos dinâmicos em pacotes de projetos.

Todos os clientes de middleware incluídos na versão Spring Cloud Alibaba 2022.0.0.0 já concluíram a adaptação para construção de aplicações nativas GraalVM. Devido à natureza específica do projeto em si, há um grande número de usos de recursos dinâmicos que não podem ser reconhecidos pelo GraalVM devido à sintaxe do Spring na implementação geral do projeto.Este conteúdo é resolvido diretamente pelo Spring AOT Engine e pela comunidade não realiza nenhum trabalho adicional de adaptação.

Além da sintaxe do sistema Spring, o próprio projeto também possui alguns outros usos dinâmicos de Java.Esta comunidade usa agente de imagem nativo para realizar análise e geração de configuração dinâmica.

Crie microsserviços baseados em compilação estática

Todos os clientes de middleware incluídos na versão Spring Cloud Alibaba 2022.0.0.0 concluíram a adaptação para construção de aplicações nativas GraalVM. Fornece aos usuários recursos de compilação estática prontos para uso. O processo de experiência de função relacionado é o seguinte:

Preparação ambiental

Primeiro você precisa instalar a distribuição GraalVM em sua máquina. Você pode baixá-lo manualmente na página do Liberica Native Image Kit ou usar um gerenciador de download como o SDKMAN!. O ambiente de demonstração deste artigo é MacOS. Se for Windows, consulte o documento correspondente [ 7] para operação. Execute o seguinte comando para instalar o ambiente GraalVM:

$ sdk install java 22.3.r17-nik
$ sdk use java 22.3.r17-nik

Verifique se a versão correta está configurada verificando a saída de java -version:

$ java -version
openjdk version "17.0.5" 2022-10-18 LTS
OpenJDK Runtime Environment GraalVM 22.3.0 (build 17.0.5+8-LTS)
OpenJDK 64-Bit Server VM GraalVM 22.3.0 (build 17.0.5+8-LTS, mixed mode)

Construção de aplicativos

Para usar o recurso de compilação estática do GraalVM para construir microsserviços, primeiro certifique-se de que a versão Spring Boot do seu projeto seja 3.0.0 ou superior, e a versão Spring Cloud seja 2022.0.0 ou superior. Em seguida, introduza as dependências do módulo necessário da versão Spring Cloud Alibaba 2022.0.0.0 no projeto.

Use os seguintes comandos para gerar os arquivos de configuração de dicas necessários para reflexão, serialização e proxy dinâmico no aplicativo, desde que o módulo pai spring-boot-starter-parent seja introduzido no aplicativo:

$ mvn -Pnative spring-boot:run

Depois disso, a aplicação será iniciada e pré-executada. Todas as funções da aplicação precisam ser testadas o mais completamente possível para garantir que a maior parte do código da aplicação seja coberta pelos casos de teste. Este processo será baseado na imagem nativa do GraalVM -agente para coletar características dinâmicas no programa, o que garante que todos os atributos dinâmicos necessários durante a execução do aplicativo sejam completamente gerados. Depois de executar todos os casos de teste, descobrimos que os seguintes arquivos de dicas serão gerados no diretório resource/META-INF/native-image:

  • resource-config.json: arquivo de dica de recurso no aplicativo
  • reflect-config.json: arquivo de dica de definição de reflexão no aplicativo
  • serialization-config.json: arquivo de dica de conteúdo de serialização no aplicativo
  • proxy-config.json: arquivo de dica de conteúdo relacionado ao proxy Java no aplicativo
  • jni-config.json: arquivo de dica de conteúdo Java Native Interface (JNI) no aplicativo

Nota: Todos os módulos principais da versão oficial do Spring Cloud Alibaba 2022.0.0.0 incluem o conteúdo de configuração exigido pelos recursos dinâmicos de seus próprios componentes em suas dependências por padrão. Portanto, o processo de pré-execução acima é principalmente para verificar o aplicativo código de negócios próprio e outros recursos dinâmicos de primeira ordem no pacote de terceiros garantem que o processo de compilação estática subsequente possa prosseguir sem problemas e o aplicativo possa iniciar normalmente.

compilação estática

Depois que as etapas acima estiverem prontas, execute o seguinte comando para construir a imagem nativa:

$ mvn -Pnative native:compile

Após a execução bem-sucedida, podemos ver o arquivo executável gerado no diretório /target.

Programa em execução

Não é diferente de um arquivo executável comum. Ao iniciar o aplicativo por meio de target/xxx, você pode observar uma saída semelhante a esta:

2023-08-01T17:21:21.006+08:00  INFO 65431 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-08-01T17:21:21.008+08:00  INFO 65431 --- [           main] c.a.cloud.imports.examples.Application   : Started Application in 0.553 seconds (process running for 0.562)

Para a nova versão do aplicativo Spring Cloud Alibaba usando a tecnologia de compilação estática GraalVM, todos os recursos principais melhoraram significativamente em termos de velocidade de inicialização e uso de memória, conforme mostrado na tabela abaixo.

foto

Nota: Os exemplos de código de teste acima vêm do módulo de exemplos do projeto Spring Cloud Alibaba, ambiente Mac 4c16g, cada conjunto de dados é testado 3 vezes e a média é obtida, e os dados específicos podem variar devido a diferentes máquinas.

Outras atualizações da comunidade

Novo site oficial on-line

Do código aberto em 2018 ao lançamento da primeira versão GA em 2019, a comunidade passou por 5 anos, o projeto lançou 35 versões e o número acumulado de estrelas excede 26k. As soluções de microsserviços Spring Cloud Alibaba são amplamente utilizadas em vários indústrias No processo de transformação digital em diversas indústrias.

Como o projeto Spring Cloud Alibaba é uma solução de microsserviço Spring Cloud baseada em padrão construída em conjunto com Spring, ele é implementado como um conjunto de soluções de tecnologia de microsserviços que incorporam décadas de experiência da Alibaba em tecnologia de microsserviços. A documentação inicial e outros conteúdos relacionados ao projeto sempre foram microsserviços no site oficial spring.io. Mas lentamente, a comunidade também descobriu que, devido à incapacidade de adicionar conteúdo chinês no spring.io, havia muitos projetos, resultando em problemas como menos projeto ou conteúdo comunitário que um único projeto poderia realizar.

Portanto, a comunidade comunicou-se com os dirigentes do Spring, com o seu apoio, e com base nos hábitos dos desenvolvedores nacionais, foi lançado oficialmente o novo site oficial da comunidade. O nome de domínio relevante é: sca.aliyun.com, onde sca é a sigla do projeto Spring Cloud Alibaba.

foto

Introdução ao novo committer

A comunidade Spring Cloud Alibaba viu vários colaboradores externos participando ativamente nas iterações de manutenção da comunidade nos últimos meses. Gostaria de expressar minha gratidão a eles! Além disso, para Liu Ziming, que tem participado de atividades comunitárias e feito contribuições importantes para o recurso, a comunidade o nomeou oficialmente como um committer da comunidade de acordo com o novo sistema de nomeação e votação de committers e votou a favor. Ele foi eleito com sucesso. Gostaria de expressar meus parabéns a ele! Mais estudantes externos são bem-vindos para prestar atenção à comunidade de código aberto Spring Cloud Alibaba e contribuir para a comunidade de código aberto.

foto

Links Relacionados:

[1] Análise do processo de inicialização de programas Java
https://shipilev.net/talks/j1-Oct2011-21682-benchmarking.pdf

[2] Plataforma de tempo de execução multilíngue de código aberto e alto desempenho GraalVM https://www.oracle.com/java/graalvm/

[3] Posicionamento externo https://www.graalvm.org/latest/reference-manual/native-image/metadata/

[4] Motor AOT
https://spring.io/blog/2021/12/09/new-aot-engine-brings-spring-native-to-the-next-level

[5] G1 GC
https://medium.com/graalvm/a-new-graalvm-release-and-new-free-license-4aab483692f5

[6] Problemas como classe de proxy dinâmico
https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html#native-image.introduzindo-graalvm-native-images.understanding - processamento aot

[7] Documento correspondente
https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311

Acho que você gosta

Origin blog.csdn.net/alisystemsoftware/article/details/132476577
Recomendado
Clasificación