Como o Quarkus combina programação imperativa e reativa

Este ano, planejamos desenvolver seriamente temas de contêiner, Java nativo da nuvem e Kubernetes . Uma continuação lógica desses tópicos será a história sobre a estrutura do Quarkus, já considerada em Habré. O artigo de hoje não se concentra tanto no “dispositivo Java ultra-rápido subatômico” como nas perspectivas que o Quarkus traz para a Enterprise. (A propósito, registre-se e acesse o nosso webinar “ Este é o framework Java nativo do Quarkus - Kubernetes ”, que será realizado em 27 de maio. Mostraremos como começar do zero ou transferir soluções prontas)



Java e JVM ainda são extremamente populares, mas, ao trabalhar com tecnologias sem servidor e microsserviços orientados à nuvem, Java e outras linguagens para JVM são usados ​​cada vez menos, pois ocupam muito espaço na memória e carregam muito lentamente, o que os torna inadequados para use com recipientes de vida curta. Felizmente, essa situação está começando a mudar graças ao Quarkus.

O Java subatômico ultra-rápido atingiu um novo nível!


42 lançamentos, 8 meses de trabalho comunitário e 177 desenvolvedores incríveis - o resultado de tudo foi o lançamento em novembro de 2019 do Quarkus 1.0 , um lançamento que marca um marco importante no desenvolvimento do projeto e oferece muitos recursos e capacidades interessantes (mais sobre eles podem ser encontrados no anúncio ) .

Hoje, contaremos como o Quarkus combina modelos de programação imperativos e reativos com base em um único núcleo reativo. Começaremos com uma breve digressão na história e, em seguida, examinaremos mais detalhadamente o que o núcleo dual do Quarkus reage e como os desenvolvedores de Java podem tirar proveito disso.

Mikroservisy , arquitetura orientada a eventos e sem servidor-funções - tudo isso hoje, como se costuma dizer, está em ascensão. Recentemente, a criação de arquiteturas baseadas em nuvem tornou-se muito mais simples e mais acessível, mas os problemas permanecem - especialmente para desenvolvedores de Java. Por exemplo, no caso de funções sem servidor e microsserviços, há uma necessidade urgente de reduzir o tempo de inicialização, reduzir o consumo de memória e tornar seu desenvolvimento mais conveniente e agradável. Nos últimos anos, o Java fez várias melhorias, como a funcionalidade de ergonomia modificada para contêineres e assim por diante. No entanto, fazer o Java funcionar no contêiner ainda não é fácil. Portanto, começaremos examinando algumas das complexidades intrínsecas do Java, que são especialmente agudas ao desenvolver aplicativos Java orientados a contêineres.

Primeiro, vamos voltar à história.


Córregos e contêineres


A partir da versão 8u131, o Java possui contêineres mais ou menos suportados devido a melhorias na funcionalidade ergonômica. Em particular, a JVM agora sabe em quantos núcleos de processador é executada e pode configurar adequadamente conjuntos de encadeamentos - normalmente conjuntos de bifurcação / junção. Obviamente, isso é ótimo, mas digamos que temos um aplicativo Web tradicional que usa servlets HTTP e roda no Tomcat, Jetty e assim por diante. Como resultado, esse aplicativo fornecerá a cada solicitação um fluxo separado e permitirá bloquear esse fluxo enquanto aguarda operações de E / S, por exemplo, ao acessar um banco de dados, arquivos ou outros serviços. Ou seja, o tamanho desse aplicativo não depende do número de núcleos disponíveis, mas do número de solicitações simultâneas. Além disso, isso significa que cotas ou limites no Kubernetes pelo número de núcleos não ajudarão particularmente aqui,e o negócio terminará em trote.

Falta de memória


Fluxos são memória. E as restrições de memória dentro do contêiner não são de forma alguma uma panacéia. Basta começar a aumentar o número de aplicativos e threads e, mais cedo ou mais tarde, você encontrará um aumento crítico na frequência de comutação e, como resultado, com a degradação do desempenho. Além disso, se o aplicativo usar estruturas tradicionais de microsserviço ou se conectar ao banco de dados, ou usar cache, ou consumir memória de alguma forma adicional, você precisará absolutamente de uma ferramenta que permita que você olhe dentro da JVM e veja como ela gerencia a memória, e não mate A própria JVM (por exemplo, XX: + UseCGroupMemoryLimitForHeap). E, apesar do fato de que, começando com o Java 9, a JVM aprendeu a aceitar cgroups e a se adaptar adequadamente, o backup e o gerenciamento de memória continuam sendo um assunto bastante complicado.

Cotas e limites


O Java 11 introduziu o suporte para cotas de CPU (como PreferContainerQuotaForCPUCount). O Kubernetes também oferece suporte a limites e cotas. Sim, tudo isso faz sentido, mas se o aplicativo novamente ultrapassar a cota alocada, chegamos novamente à conclusão de que o tamanho - como é o caso dos aplicativos Java tradicionais - é determinado pelo número de núcleos e pela alocação de um encadeamento separado para cada solicitação. há pouco sentido nisso tudo.
Além disso, se você usar cotas e limites ou funções de dimensionamento horizontal (dimensionamento horizontal) da plataforma subjacente ao Kubernetes, o problema também não será resolvido. Simplesmente gastamos mais recursos na solução do problema original ou, como resultado, acabamos usando recursos. E se for um sistema altamente carregado em uma nuvem pública pública, quase certamente começaremos a usar mais recursos do que realmente precisamos.

E o que fazer com tudo isso?


Se de uma maneira simples, use bibliotecas e estruturas de E / S assíncronas e sem bloqueio, como Netty, Vert.x ou Akka. Eles são muito mais adequados para trabalhar em contêineres devido à sua natureza reativa. Graças à E / S sem bloqueio, o mesmo encadeamento pode processar várias solicitações simultâneas ao mesmo tempo. Enquanto uma solicitação está aguardando resultados de E / S, seu encadeamento de processamento é liberado e recebido para outra solicitação. E quando os resultados de E / S finalmente chegam, o processamento da primeira solicitação continua. Ao alternar o processamento de solicitações no mesmo fluxo, é possível reduzir o número total de encadeamentos e reduzir o consumo de recursos para processar solicitações.

Com E / S sem bloqueio, o número de núcleos se torna um parâmetro-chave, pois determina o número de encadeamentos de E / S que podem ser executados em paralelo. Quando usado corretamente, isso permite distribuir efetivamente a carga entre os núcleos e lidar com cargas mais altas com menos recursos.

Como e isso é tudo?


Não, há mais uma coisa. A programação reativa ajuda a fazer melhor uso dos recursos, mas também tem um preço. Em particular, o código terá que ser reescrito de acordo com os princípios de não bloqueio e evitar o bloqueio de fluxos de entrada e saída. E este é um modelo completamente diferente de desenvolvimento e implementação. E embora existam muitas bibliotecas úteis, essa ainda é uma mudança fundamental na maneira usual de pensar.

Primeiro, você precisa aprender a escrever código que é executado de forma assíncrona. Depois de começar a usar E / S sem bloqueio, é necessário prescrever explicitamente o que deve acontecer quando você receber uma resposta à solicitação. Apenas bloquear e esperar falhará. Em troca, você pode transmitir retornos de chamada, usar programação reativa ou continuação. Mas isso não é tudo: para usar E / S sem bloqueio, você precisa de servidores e clientes sem bloqueio, e de preferência em qualquer lugar. No caso do HTTP, tudo é simples, mas também há um banco de dados, sistemas de arquivos e muito mais.

Embora a reatividade total de ponta a ponta ofereça eficiência máxima, essa mudança pode ser difícil de digerir na prática. Portanto, a capacidade de combinar código reativo e imperativo se torna uma condição necessária para:

  1. Use efetivamente os recursos nas áreas mais carregadas do sistema de software;
  2. Use um código de estilo mais simples em suas outras partes.

Apresentando o Quarkus


Na verdade, essa é a essência do Quarkus - combinar modelos reativos e imperativos em um ambiente de tempo de execução.

O Quarkus é baseado no Vert.x e no Netty, além dos quais várias estruturas e extensões reativas são usadas para ajudar o desenvolvedor. O Quarkus foi projetado para criar não apenas microsserviços HTTP, mas também arquiteturas orientadas a eventos. Devido à sua natureza reativa, ele funciona de maneira muito eficiente com sistemas de mensagens (Apache Kafka, AMQP, etc.).

O truque é como usar o mesmo mecanismo a jato para códigos imperativos e reativos.



Quarkus faz isso de forma brilhante. A escolha entre imperativo e reativo é óbvia - usar um e outro núcleo reativo. E com o que ajuda muito, é com o código rápido e sem bloqueio que processa quase tudo o que passa pelo segmento de loop de eventos (thread de loop de eventos, também conhecido como thread de E / S). Porém, se você possui aplicativos REST ou do lado do cliente clássicos, o Quarkus está pronto para um modelo de programação imperativo. Por exemplo, o suporte HTTP no Quarkus é baseado no uso de um mecanismo a jato e sem bloqueio (Eclipse Vert.x e Netty). Todas as solicitações HTTP recebidas pelo seu aplicativo passam primeiro pelo loop de eventos (IO Thread) e depois são enviadas para a parte do código que gerencia as solicitações.Dependendo do destino, o código de controle de solicitação pode ser chamado em um thread separado (o chamado thread de trabalho, usado no caso de servlets e Jax-RS) ou usar o fluxo de entrada e saída original (rota reativa da rota reativa).



Clientes sem bloqueio que trabalham na parte superior do mecanismo Vert.x são usados ​​para conectores de sistemas de mensagens. Portanto, você pode enviar, receber e processar mensagens com eficiência de sistemas de classe de middleware de mensagens.

O site Quarkus.io coletou algumas boas diretrizes para ajudar você a começar com o Quarkus:


Além disso, preparamos lições práticas on-line para se familiarizar com vários aspectos da programação reativa; além disso, apenas um navegador é suficiente para completá-las, nenhum IDE é necessário para isso e um computador não é necessário. Encontre essas lições aqui .

Recursos úteis




10 tutoriais em vídeo do Quarkus para se familiarizar com o tópico


De acordo com o site Quarkus.io , o Quarkus é uma pilha Java orientada ao Kubernetes , personalizada para GraalVM e OpenJDK HotSpot e compilada a partir das melhores bibliotecas e padrões Java.

Para ajudar você a entender o tópico, selecionamos 10 tutoriais em vídeo que abordam vários aspectos do Quarkus e exemplos de seu uso:

1. Apresentando o Quarkus: o Java Framework de próxima geração para o Kubernetes


Autores: Thomas Qvarnstrom e Jason Greene
O objetivo do projeto Quarkus é criar uma plataforma Java para Kubernetes e ambientes sem servidor e combinar modelos de programação reativos e imperativos em um único tempo de execução, para que os desenvolvedores pode variar de maneira flexível a abordagem ao trabalhar com uma ampla variedade de arquiteturas de aplicativos distribuídas. Aprenda mais com a palestra introdutória abaixo.



2. Quarkus: Java subatômico ultra-rápido


Autor: Burr Sutter Um
tutorial em vídeo da palestra online do DevNation Live demonstra como usar o Quarkus para otimizar aplicativos Java corporativos, APIs, microsserviços e recursos sem servidor no Kubernetes / OpenShift, tornando-os muito menores, mais rápidos e mais escaláveis.



3. Quarkus e GraalVM: aceleramos o Hibernate para super velocidades e comprimimos para tamanhos subatômicos


Autor: Sane Grinovero
A partir da apresentação, você aprenderá como o Quarkus apareceu, como funciona e como permite criar bibliotecas complexas como o Hibernate ORM compatíveis com imagens nativas do GraalVM.



4. Aprendendo a desenvolver aplicativos sem servidor


Publicado por Marthen Luther
O vídeo abaixo mostra como criar um aplicativo Java simples usando o Quarkus e implantá-lo como um aplicativo sem servidor no Knative.



5. Quarkus: codifique com prazer


Postado por Edson Yanaga
Wideguide para criar seu primeiro projeto do Quarkus para entender por que o Quarkus está conquistando os corações dos desenvolvedores.



6. Java e contêineres - qual será o seu futuro comum


Postado por Mark Little
Esta apresentação apresenta a história do Java e explica por que o Quarkus é o futuro do Java.



7. Quarkus: Java subatômico ultra-rápido


Autor: Dimitris Andreadis Dimitris Andreadis
Uma visão geral dos desenvolvedores aclamados da Quarkus: simplicidade, velocidades ultra-rápidas, principais bibliotecas e padrões.



8. Quarkus e sistemas reativos subatômicos


Publicado por Clement Escoffier
Por meio da integração com o GraalVM, o Quarkus fornece uma experiência de desenvolvimento super-rápida e um tempo de execução subatômico. O autor fala sobre o lado reativo do Quarkus e como usá-lo ao criar aplicativos reativos e aplicativos de streaming.



9. Quarkus e rápido desenvolvimento de aplicativos no Eclipse MicroProfile


Publicado por John Clingan Ao
combinar o Eclipse MicroProfile e o Quarkus, os desenvolvedores podem criar aplicativos de contêineres MicroProfile totalmente funcionais que são executados em algumas dezenas de milissegundos. O vídeo detalha como codificar o aplicativo de contêiner MicroProfile para implantação na plataforma Kubernetes.



10. versão Java, Turbo


Publicado por Marcus Biel
O autor mostra como usar o Quarkus para criar contêineres Java super pequenos e super rápidos para uma inovação real, especialmente em ambientes sem servidor.


All Articles