Este ano, pretendemos desenvolver seriamente os temas de contêineres, e . A continuação lógica desses tópicos será uma discussão sobre o framework Quarkus, já no Habr. O artigo de hoje não se concentra tanto na essência da "Java subatômica super-rápida", mas nas perspectivas que o Quarkus traz para o ambiente Enterprise.

Java e JVM continuam extremamente populares, mas ao trabalhar com tecnologias sem servidor e microserviços orientados para a nuvem, Java e outras linguagens para JVM estão sendo usadas com menos frequência, pois ocupam muito espaço na memória e demoram para carregar, o que as torna pouco adequadas para uso com contêineres de vida curta. Felizmente, essa situação está começando a mudar graças ao Quarkus.
A Java subatômica super-rápida alcançou um novo nível!
42 lançamentos, 8 meses de trabalho da comunidade e 177 desenvolvedores incríveis resultaram no lançamento em novembro de 2019 , uma versão que marca um marco importante no desenvolvimento do projeto e oferece uma série de funções e recursos incríveis (você pode ler mais sobre eles em ).
Hoje, vamos mostrar como o Quarkus une os modelos de programação imperativa e reativa com uma única estrutura reativa. Começaremos com uma breve excursão pela história e, em seguida, analisaremos detalhadamente o que constitui o dualismo do núcleo reativo do Quarkus e como -desenvolvedores podem aproveitar essas vantagens.
, e -funções – tudo isso, hoje em dia, está, por assim dizer, em alta. Recentemente, a criação de arquiteturas orientadas para a nuvem tornou-se muito mais fácil e acessível, mas os problemas persistem – especialmente para os desenvolvedores Java. Por exemplo, no caso de funções sem servidor e microserviços, há uma necessidade urgente de reduzir o tempo de inicialização, diminuir o consumo de memória e tornar seu desenvolvimento mais conveniente e agradável. Nos últimos anos, Java fez várias melhorias, como a funcionalidade ergonomics aprimorada para contêineres, entre outras. No entanto, ainda assim, conseguir que o Java funcione corretamente em um contêiner continua sendo um desafio. Portanto, começaremos examinando algumas das complexidades internas do Java, que se manifestam de forma particularmente aguda ao desenvolver aplicações Java orientadas a contêineres.
Primeiro, vamos olhar para a história.

Fluxos e contêineres
A partir da versão 8u131, o Java começou a oferecer um suporte razoável para contêineres, graças a melhorias na funcionalidade de ergonomia. Em particular, agora a JVM sabe em quantos núcleos de processador está sendo executada e pode ajustar pools de threads de acordo – geralmente, pools fork/join. Sem dúvida, isso é ótimo, mas, digamos, temos uma aplicação web tradicional que utiliza servlets HTTP e é executada em Tomcat, Jetty, etc. Como resultado, essa aplicação criará um thread separado para cada solicitação e permitirá que essa thread fique bloqueada enquanto aguarda operações de entrada/saída, por exemplo, ao acessar bancos de dados, arquivos ou outros serviços. Ou seja, o tamanho de tal aplicativo depende não da quantidade de núcleos disponíveis, mas do número de solicitações simultâneas. Além disso, isso significa que quotas ou limites em Kubernetes sobre a quantidade de núcleos não serão muito úteis, e acabaremos enfrentando throttling.
Exaustão de memória
As threads são memória. E as limitações de memória dentro do contêiner não são uma panaceia. Comece a aumentar o número de aplicativos e threads, e cedo ou tarde você enfrentará um crescimento crítico na frequência de troca de contexto e, como resultado, uma degradação no desempenho. Além disso, se o aplicativo utilizar frameworks de microserviços tradicionais ou se conectar a bancos de dados, ou utilizar cache, ou de alguma outra forma gastar memória, você definitivamente precisará de uma ferramenta que permita olhar dentro da JVM e ver como ela gerencia a memória, sem que a própria JVM seja prejudicada (por exemplo, XX:+UseCGroupMemoryLimitForHeap). E mesmo que, a partir do Java 9, a JVM tenha aprendido a entender cgroups e se adaptar adequadamente, a reserva e o gerenciamento de memória continuam a ser questões bastante complicadas.
Quotas e limites
Com o Java 11, o suporte a quotas de CPU foi introduzido (como PreferContainerQuotaForCPUCount). O Kubernetes também oferece suporte a limites e quotas. Sim, tudo isso faz sentido, mas, se o aplicativo novamente ultrapassar a quota designada, voltamos à situação em que o tamanho – assim como no caso de aplicativos Java tradicionais – é determinado pelo número de núcleos, com a alocação de uma thread separada para cada solicitação, ou seja, o benefício de tudo isso se torna limitado.
Além disso, se utilizarmos quotas e limites ou funções de escalonamento horizontal (scale-out) da plataforma subjacente ao Kubernetes, o problema não se resolve por si só. Estamos apenas gastando mais recursos para resolver o problema original ou, no final, acabamos com um desperdício de recursos. E se isso for um sistema de alta carga em uma nuvem pública acessível, quase certamente começamos a usar mais recursos do que realmente precisamos.
E o que fazer com tudo isso?
Se formos diretos, devemos usar bibliotecas e frameworks assíncronos e não bloqueantes de entrada e saída, como o Netty, ou Akka. Eles são muito mais adequados para trabalhar em contêineres devido à sua natureza reativa. Com a entrada e saída não bloqueantes, o mesmo thread pode lidar com várias requisições simultaneamente. Enquanto uma requisição aguarda resultados de entrada e saída, o thread que a processa se libera e assume outra requisição. Quando os resultados de entrada e saída finalmente chegam, o processamento da primeira requisição continua. Alternando o processamento de requisições dentro do mesmo thread, é possível reduzir o número total de threads e diminuir o consumo de recursos para o processamento das requisições.
Com a entrada e saída não bloqueantes, o número de núcleos se torna um parâmetro crucial, pois é isso que determina o número de threads de entrada e saída que podem ser executadas em paralelo. Quando utilizado corretamente, isso permite distribuir a carga de forma eficiente entre os núcleos e lidar com cargas mais altas com menos recursos.
Como, e é tudo isso?
Não, há mais. A programação reativa ajuda a utilizar melhor os recursos, mas também tem seu custo. Em particular, o código precisará ser reescrito de acordo com os princípios de não bloqueio e evitar bloqueios de threads de entrada e saída. E essa é uma modelo de desenvolvimento e execução completamente diferente. Embora existam muitas bibliotecas úteis, isso ainda representa uma mudança radical na forma de pensar habitual.
Primeiro, você precisa aprender a escrever código que seja executado de forma assíncrona. Assim que você começa a usar entrada e saída não bloqueantes, é necessário especificar claramente o que deve acontecer ao receber uma resposta para uma solicitação. Bloquear e esperar não é mais uma opção. Em vez disso, você pode passar callbacks, usar programação reativa ou continuação. Mas isso não é tudo: para usar entrada e saída não bloqueantes, você também precisa de servidores e clientes não bloqueantes, de preferência em todos os lugares. No caso do HTTP, é simples, mas existem também bancos de dados, sistemas de arquivos e muito mais.
E embora a reatividade total ofereça máxima eficiência, 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 que:
- Utilize os recursos de forma eficaz nas áreas mais carregadas do sistema de software;
- Use um código de estilo mais simples nas outras partes.
Apresentamos o Quarkus
Na verdade, essa é a essência do Quarkus – combinar modelos reativos e imperativos em um único ambiente de execução.
A base do Quarkus é formada pelo Vert.x e pelo Netty, sobre os quais é utilizado uma gama de frameworks reativos e extensões, projetados para ajudar o desenvolvedor. O Quarkus é destinado à construção não apenas de microsserviços HTTP, mas também de arquiteturas baseadas em eventos. Graças à sua natureza reativa, ele funciona de maneira muito eficaz com sistemas de troca de mensagens (Apache Kafka, AMQP etc.).
O truque está em como usar o mesmo motor reativo tanto para código imperativo quanto para código reativo.

Quarkus se destaca nesse aspecto. A escolha entre o imperativo e o reativo é clara – usar um núcleo reativo para ambos. E onde ele realmente ajuda é com código não bloqueante rápido que processa quase tudo o que passa pelo ciclo de eventos (event-loop thread, também conhecido como IO thread). Mas se você tem aplicativos REST clássicos ou aplicativos do lado do cliente, Quarkus tem uma modelo de programação imperativa pronta para uso. Por exemplo, o suporte a HTTP em Quarkus é construído com base em um mecanismo não bloqueante e reativo (Eclipse Vert.x e Netty). Todas as solicitações HTTP recebidas pelo seu aplicativo passam primeiro pelo ciclo de eventos (IO Thread) e, em seguida, são enviadas para a parte do código que gerencia as solicitações. Dependendo do destino, o código de gerenciamento de solicitações pode ser chamado dentro de uma thread separada (o chamado worker thread, utilizado em servlets e Jax-RS) ou pode utilizar o próprio thread de entrada e saída (o chamado reactive route).

Para conectores de sistemas de mensagem, são utilizados clientes não bloqueantes que operam sobre o motor Vert.x. Portanto, você pode enviar, receber e processar mensagens de forma eficaz a partir de sistemas de middleware de mensagens.
está escrito: um conjunto de bons tutoriais foi reunido para ajudar a começar a trabalhar com Quarkus:
Além disso, preparamos aulas práticas online para familiarizá-lo com vários aspectos da programação reativa, e para completá-las, tudo o que você precisa é de um navegador — não é necessário IDE e nem mesmo um computador. Você pode encontrar essas aulas em .
Recursos Úteis
- Site do projeto Quarkus –
- Projeto Quarkus no GitHub –
- Twitter do projeto Quarkus –
- Chat do projeto Quarkus –
- Fóruns do projeto Quarkus – !forum/quarkus-dev
10 vídeos tutoriais sobre Quarkus para você se familiarizar com o assunto
Como está escrito no site , é - uma pilha Java orientada para GraalVM e OpenJDK HotSpot, construída a partir das melhores bibliotecas e padrões Java.
Para ajudá-lo a entender o assunto, selecionamos 10 vídeos tutoriais que abordam diversos aspectos do Quarkus e exemplos de seu uso:
1. Apresentando Quarkus: um framework Java de nova geração para Kubernetes
Autoras: Thomas Qvarnstrom e Jason Greene
O objetivo do projeto Quarkus é criar uma plataforma Java para Kubernetes e ambientes serverless, além de unir modelos de programação reativa e imperativa em um único ambiente de execução, permitindo que os desenvolvedores variem flexivelmente sua abordagem ao trabalhar com uma ampla gama de arquiteturas de aplicativos distribuídos. Saiba mais na palestra introdutória abaixo.

2. Quarkus: Java subatômica super-rápida
Autor: Burr Sutter
O tutorial em vídeo do DevNation Live demonstra como usar o Quarkus para otimizar aplicativos Java corporativos, APIs, microsserviços e funções serverless no ambiente Kubernetes/OpenShift, tornando-os muito menores, mais rápidos e escaláveis.

3. Quarkus e GraalVM: acelerando Hibernate a velocidades super rápidas e comprimindo a tamanhos subatômicos
Autor: Sanne Grinovero
Na apresentação, você descobrirá como o Quarkus surgiu, como funciona e como torna bibliotecas complexas, como o Hibernate ORM, compatíveis com imagens nativas do GraalVM.

4. Aprendendo a desenvolver aplicações serverless
Autor: Marthen Luther
No vídeo abaixo, é mostrado como criar um simples aplicativo Java usando o Quarkus e implantá-lo como um aplicativo serverless no Knative.

5. Quarkus: codifique com prazer
Autor: Edson Yanaga
Guia em vídeo para criar seu primeiro projeto Quarkus, permitindo entender por que o Quarkus está conquistando os corações dos desenvolvedores.

6. Java e containers – qual será seu futuro em conjunto
Autor: 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ômica super-rápida
Autor: Dimitris Andreadis
Visão geral das vantagens do Quarkus, que foram reconhecidas pelos desenvolvedores: simplicidade, altíssimas velocidades, melhores bibliotecas e padrões.

8. Quarkus e sistemas reativos subatômicos
Autor: Clement Escoffier
Graças à integração com o GraalVM, o Quarkus proporciona uma experiência de desenvolvimento super-rápida e um ambiente de execução subatômico. O autor fala sobre o lado reativo do Quarkus e como usá-lo ao criar aplicativos reativos e aplicativos com streaming de dados.

9. Quarkus e desenvolvimento rápido de aplicativos no Eclipse MicroProfile
Autor: John Clingan
Combinando Eclipse MicroProfile e Quarkus, os desenvolvedores podem criar aplicativos MicroProfile em contêineres totalmente funcionais que são iniciados em apenas algumas dezenas de milissegundos. O vídeo detalha como codificar um aplicativo MicroProfile para ser implantado na plataforma Kubernetes.

10. Java, versão "Turbo"
Autor: Marcus Biel
O autor mostra como usar Quarkus para criar contêineres Java super pequenos e super rápidos, permitindo uma verdadeira revolução, especialmente em ambientes serverless.

Fonte: habr.com
