Como o Quarkus combina programação imperativa e reativa

Este ano planejamos desenvolver seriamente temas de contêineres, Java nativo da nuvem и Kubernetes. Uma continuação lógica desses tópicos será uma história sobre o framework Quarkus, já considerado em Habré. O artigo de hoje é menos sobre o design do “Java subatômico super rápido” e mais sobre a promessa que o Quarkus traz para a empresa.

Como o Quarkus combina programação imperativa e reativa

Java e JVM ainda são extremamente populares, mas ao trabalhar com tecnologias sem servidor e microsserviços nativos da nuvem, Java e outras linguagens JVM são cada vez menos usadas porque ocupam muito espaço de memória e são muito lentos para carregar, tornando-os pouco adequado para uso com recipientes de curta duração. Felizmente, esta situação está começando a mudar graças ao Quarkus.

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

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

Hoje mostraremos como o Quarkus combina modelos de programação imperativos e reativos em um único núcleo reativo. Começaremos com uma breve história e depois entraremos em detalhes sobre o que é o dualismo central reativo de Quarkus e como Java-Os desenvolvedores podem aproveitar esses benefícios.

Microsserviços, arquiteturas orientadas a eventos и sem servidor-funções – tudo isso está, como dizem, em alta hoje. Recentemente, a criação de arquiteturas centradas na nuvem tornou-se muito mais fácil e acessível, mas os problemas permanecem – especialmente para desenvolvedores Java. Por exemplo, no caso de funções serverless e microsserviços, há uma necessidade urgente de reduzir o tempo de inicialização, reduzir o consumo de memória e ainda tornar seu desenvolvimento mais conveniente e agradável. Java fez diversas melhorias nos últimos anos, como funcionalidade ergonômica aprimorada para contêineres e assim por diante. No entanto, fazer com que o Java funcione corretamente em um contêiner ainda é um desafio. Portanto, começaremos examinando algumas das complexidades inerentes ao Java, que são particularmente graves no desenvolvimento de aplicativos Java orientados a contêineres.

Primeiro, vamos dar uma olhada na história.

Como o Quarkus combina programação imperativa e reativa

Fluxos e contêineres

A partir da versão 8u131, o Java começou a suportar mais ou menos contêineres devido a melhorias na funcionalidade ergonômica. Em particular, a JVM agora sabe em quantos núcleos de processador está sendo executada e pode configurar pools de threads — normalmente pools de bifurcação/junção — de acordo. Claro, isso é ótimo, mas digamos que temos uma aplicação web tradicional que usa servlets HTTP e roda em Tomcat, Jetty, etc. Como resultado, este aplicativo dará a cada solicitação um thread separado e permitirá que ele bloqueie esse thread enquanto aguarda operações de E/S, por exemplo, ao acessar o banco de dados, arquivos ou outros serviços. Ou seja, o tamanho de tal aplicação não depende da quantidade de núcleos disponíveis, mas sim da quantidade de solicitações simultâneas. Além disso, isso significa que cotas ou limites no número de núcleos no Kubernetes não ajudarão muito aqui, e o assunto acabará em estrangulamento.

Esgotamento da memória

Threads são memória. E as limitações de memória intra-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, degradação do desempenho. Além disso, se o seu aplicativo usa estruturas tradicionais de microsserviços, ou se conecta a um banco de dados, ou usa cache, ou usa memória de outra forma, você obviamente precisa de uma ferramenta que permita olhar dentro da JVM e ver como ela gerencia a memória sem eliminá-la. A própria JVM (por exemplo, XX:+UseCGroupMemoryLimitForHeap). E mesmo que, desde o Java 9, a JVM tenha aprendido a aceitar cgroups e a se adaptar de acordo, reservar e gerenciar memória continua sendo uma questão bastante complexa.

Cotas e limites

Java 11 introduziu suporte para cotas de CPU (como PreferContainerQuotaForCPUCount). O Kubernetes também oferece suporte para limites e cotas. Sim, tudo isso faz sentido, mas se a aplicação ultrapassar novamente a cota alocada, acabamos novamente com o tamanho - como é o caso das aplicações Java tradicionais - determinado pelo número de núcleos e com a alocação de um thread separado para cada pedido, então há pouco sentido em tudo isto.
Além disso, se você usar cotas e limites ou as funções de expansão da plataforma subjacente ao Kubernetes, o problema também não se resolverá. Simplesmente gastamos mais recursos para resolver o problema original ou acabamos gastando demais. E se for um sistema de alta carga em uma nuvem pública, é quase certo que acabaremos usando mais recursos do que realmente precisamos.

E o que fazer com tudo isso?

Simplificando, 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 thread pode processar várias solicitações simultâneas. Enquanto uma solicitação aguarda resultados de E/S, o thread que a processa é liberado e assumido por outra solicitação. E quando os resultados de E/S finalmente chegam, o processamento da primeira solicitação continua. Ao processar solicitações intercaladas no mesmo thread, você pode reduzir o número total de threads 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 porque determina o número de threads 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 de trabalho maiores com menos recursos.

Como, isso é tudo?

Não, há outra coisa. A programação reativa ajuda a utilizar melhor os 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 threads de E/S. E este é um modelo de desenvolvimento e execução completamente diferente. E embora existam muitas bibliotecas úteis aqui, ainda é uma mudança radical na forma usual de pensar.

Primeiro, você precisa aprender como escrever código que seja executado de forma assíncrona. Depois de começar a usar E/S sem bloqueio, você precisa especificar explicitamente o que deve acontecer quando uma resposta a uma solicitação for recebida. Simplesmente bloquear e esperar não funcionará mais. Em vez disso, você pode passar 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, de preferência em qualquer lugar. No caso do HTTP tudo é simples, mas também existem bancos de dados, sistemas de arquivos e muito mais.

E embora a reatividade total de ponta a ponta maximize a eficiência, essa mudança pode ser difícil de tolerar na prática. Portanto, a capacidade de combinar código reativo e imperativo torna-se um pré-requisito para:

  1. Utilizar eficazmente os recursos nas áreas mais carregadas do sistema de software;
  2. Use código de estilo mais simples nas partes restantes.

Apresentando o Quarkus

Na verdade, esta é a essência do Quarkus – combinar modelos reativos e imperativos em um único ambiente de execução.

Quarkus é baseado em Vert.x e Netty, com uma variedade de estruturas e extensões reativas para ajudar o desenvolvedor. O Quarkus foi projetado para construir não apenas microsserviços HTTP, mas também arquiteturas orientadas a eventos. Devido à sua natureza reativa, funciona de forma muito eficaz com sistemas de mensagens (Apache Kafka, AMQP, etc.).

O truque é como usar o mesmo mecanismo reativo para código imperativo e reativo.

Como o Quarkus combina programação imperativa e reativa

Quarkus faz isso de maneira brilhante. A escolha entre imperativo e reativo é óbvia – use um kernel reativo para ambos. O que realmente ajuda é o código rápido e sem bloqueio que lida com quase tudo que passa pelo thread do loop de eventos, também conhecido como thread IO. Mas se você tiver aplicações REST clássicas ou do lado do cliente, o Quarkus tem um modelo de programação imperativo pronto. Por exemplo, o suporte HTTP no Quarkus é baseado no uso de um mecanismo reativo e não bloqueador (Eclipse Vert.x e Netty). Todas as solicitações HTTP recebidas pela sua aplicação passam primeiro por um 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 gerenciamento de solicitação pode ser chamado dentro de um thread separado (o chamado thread de trabalho, usado no caso de servlets e Jax-RS) ou usar o thread de E/S de origem (rota reativa).

Como o Quarkus combina programação imperativa e reativa

Os conectores do sistema de mensagens usam clientes sem bloqueio executados no mecanismo Vert.x. Portanto, você pode enviar, receber e processar mensagens com eficiência de sistemas de middleware de mensagens.

O site Quarkus.io Aqui estão alguns bons tutoriais para ajudá-lo a começar a usar o Quarkus:

Também criamos tutoriais práticos on-line para ensinar vários aspectos da programação reativa em apenas um navegador, sem necessidade de IDE e sem necessidade de computador. Você pode encontrar essas lições aqui.

Recursos úteis

10 videoaulas sobre Quarkus para se familiarizar com o tema

Como dizem no site Quarkus.io, quarks - É KubernetesPilha Java orientada para Java, adaptada para GraalVM e OpenJDK HotSpot e montada a partir das melhores bibliotecas e padrões Java.

Para ajudar você a entender o assunto, selecionamos 10 tutoriais em vídeo que abordam diversos aspectos do Quarkus e exemplos de seu uso:

1. Apresentando Quarkus: o framework Java de última geração para Kubernetes

Por 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 ambiente de tempo de execução para que os desenvolvedores possam variar com flexibilidade 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ômico super rápido

Por: Burr Sutter
Este tutorial em vídeo do DevNation Live demonstra como usar o Quarkus para otimizar aplicativos Java corporativos, APIs, microsserviços e funções sem servidor em um ambiente Kubernetes/OpenShift, tornando-os muito menores, mais rápidos e mais escaláveis.

3. Quarkus e GraalVM: acelerando o Hibernate para supervelocidades e reduzindo-o para tamanhos subatômicos

Autor: Sanne Grinovero
Na apresentação você aprenderá como o Quarkus surgiu, como ele funciona e como permite tornar bibliotecas complexas, como o Hibernate ORM, compatíveis com imagens nativas do GraalVM.

4. Aprenda a desenvolver aplicativos sem servidor

Autor: Martinho Lutero
O vídeo abaixo mostra como criar um aplicativo Java simples usando Quarkus e implantá-lo como um aplicativo sem servidor no Knative.

5. Quarkus: divirta-se codificando

Autor: Edson Yanaga
Um guia em vídeo para criar seu primeiro projeto Quarkus, permitindo que você entenda por que o Quarkus está conquistando os corações dos desenvolvedores.

6. Java e contêineres – qual será o futuro deles juntos

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

7. Quarkus: Java subatômico super rápido

Autor: Dimitris Andreadis
Uma visão geral das vantagens do Quarkus que receberam reconhecimento dos desenvolvedores: simplicidade, velocidades ultra-altas, as melhores bibliotecas e padrões.

8. Quarkus e sistemas de foguetes subatômicos

Autor: Clement Escoffier
Através da integração com GraalVM, o Quarkus oferece uma experiência de desenvolvimento ultrarrápida e um ambiente de execução subatômico. O autor fala sobre o lado reativo do Quarkus e como usá-lo para construir aplicações reativas e de streaming.

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

Autor: John Cligan
Ao combinar o Eclipse MicroProfile e o Quarkus, os desenvolvedores podem criar aplicativos MicroProfile em contêineres completos que são iniciados em dezenas de milissegundos. O vídeo detalha como codificar um aplicativo MicroProfile em contêiner para implantação na plataforma Kubernetes.

10. Java, versão "Turbo"

Autor: Marcus Biel
O autor mostra como usar o Quarkus para criar contêineres Java superpequenos e super-rápidos que permitem avanços reais, especialmente em ambientes sem servidor.



Fonte: habr.com

Adicionar um comentário