Launch Predator - Repositórios de dados pré-compilados


Hoje, a equipe Micronaut da Object Computing Inc (OCI) apresentou o Predator , um novo projeto de código aberto cujo objetivo é melhorar significativamente o tempo de execução e o desempenho (da memória) do acesso a dados para microsserviços e aplicativos sem servidor, sem perder a produtividade em comparação com ferramentas como GORM e Spring Data.


Histórico das Ferramentas de Acesso a Dados


Podemos rastrear o histórico do modelo de repositório de dados desde 2004, quando o Ruby on Rails saiu com o subsistema ActiveRecord, uma API que revolucionou nossa compreensão do acesso a dados em termos de produtividade do desenvolvedor.


Em 2007, a equipe do Grails introduziu uma API semelhante ao ActiveRecord para a JVM - GORM (parte do Grails). O GORM confiou na natureza dinâmica do Groovy para implementar métodos de pesquisa no Hibernate e forneceu os mesmos benefícios de produtividade para os usuários da JVM.


Como o GORM depende da linguagem Groovy, foi criado em 2011 um projeto Spring Data que permitiu aos desenvolvedores Java definir métodos de pesquisa, como findByTitle , na interface e implementar automaticamente a lógica de consulta em tempo de execução.


Como as ferramentas de acesso a dados funcionam


Todas as implementações mencionadas usam o mesmo modelo, que é construir um metamodelo de entidades do projeto em tempo de execução que modela os relacionamentos entre suas classes de entidades. No Spring Data, é um MappingContext e, no GORM, também é chamado de MappingContext. Eles são construídos pela varredura de classes usando reflexão. (A semelhança na nomeação não é acidental aqui. Em 2010, trabalhei com a equipe do Spring Data para tentar recriar o GORM para Java, em um projeto que acabou se transformando no que hoje é chamado Spring Data)


Esse metamodelo é usado para transformar uma expressão de pesquisa, como bookRepository.findByTitle("The Stand") , em um modelo de consulta abstrata em tempo de execução, usando uma combinação de análise de expressão regular e lógica de estrutura. Precisamos de um modelo de consulta abstrato porque o dialeto de destino da consulta é diferente para cada banco de dados (SQL, JPA-QL, Cypher, Bson, etc.)


Suporte ao Repositório Micronaut


Desde o lançamento do Micronaut, há pouco mais de um ano, o principal recurso que nos faltava era o "GORM for Java" ou o suporte a Spring Data. Muitos desenvolvedores estão apaixonados pela produtividade que essas ferramentas fornecem, bem como pela facilidade de definir as interfaces que a estrutura implementa. Eu diria que a maior parte do sucesso do Grails e do Spring Boot pode ser atribuída ao GORM e ao Spring Data, respectivamente.


Para usuários do Micronaut que usavam o Groovy, tínhamos suporte ao GORM desde o primeiro dia, e os usuários do Java e Kotlin ficaram sem nada, porque precisavam implementar repositórios por conta própria.


Seria tecnicamente possível, e francamente mais fácil, simplesmente adicionar um módulo para o Micronaut que configurasse o Spring Data. No entanto, seguindo esse caminho, forneceríamos um subsistema implementado usando todos os métodos que o Micronaut tentava evitar: uso generalizado de proxies, reflexão e alto consumo de memória.


Apresentando Predator!


Predator, abreviação de Precomputed Data Repositories, usa a API Micronaut para compilar antes da execução (AoT, antecipadamente) para transferir um metamodelo de entidades e converter expressões de pesquisa (como findByTitle ) no SQL ou JPA-QL apropriado no seu compilador . Como resultado, a consulta executa uma camada de tempo de execução do programa muito fina sem reflexão e só resta executar a consulta e retornar os resultados.


O resultado é esmagador ... a partida a frio é significativamente reduzida, obtemos um consumo de memória incrivelmente baixo e uma melhoria acentuada no desempenho.


Hoje, abrimos o código-fonte do Predator sob a licença Apache 2; ele virá com duas implementações iniciais (mais recursos planejados para o futuro) para o JPA (baseado no Hibernate) e para o SQL com JDBC.


A implementação JDBC me agrada mais, pois é completamente independente da reflexão, não usa proxies e carregamento de classe dinâmica para o seu nível de acesso a dados, o que leva a um desempenho aprimorado. A camada de tempo de execução é tão leve que mesmo o código do repositório equivalente escrito à mão não será executado mais rapidamente.


Predador de desempenho


Como o Predator não precisa executar nenhuma transformação de consulta em tempo de execução, o ganho de desempenho é significativo. No mundo da utilização da computação em nuvem, em que você paga pelo tempo que seu aplicativo executa ou pela execução de uma única função, os desenvolvedores geralmente perdem de vista o desempenho de seus mecanismos de acesso a dados.


A tabela a seguir resume as diferenças de desempenho que podem ser esperadas para uma expressão de pesquisa simples, como findByTitle , em comparação com outras implementações. Todos os testes foram realizados usando uma bancada de testes no Xeon iMac Pro de 8 núcleos nas mesmas condições, os testes estão abertos e podem ser encontrados no repositório :


ImplementaçãoOperações por segundo
Predator JDBC225K ops / s
Predator jpa130K ops / s
Jpa de dados do Spring90K ops / s
GORM JPA50K ops / s
Spring Data JDBCLocalizadores não suportados

Sim, você leu certo. Com o Predator JDBC, você pode esperar um aumento de quase quatro vezes o desempenho em relação ao GORM e 2,5 vezes em relação ao Spring Data.


E mesmo se você usar o Predator JPA, poderá contar com mais de 2X melhorias de desempenho em comparação com o GORM e um aumento de até 40% em comparação com o Spring Data JPA.


Observe a diferença no tamanho da pilha de execução ao usar o Predator em comparação com as alternativas:


Predador:



JPA Predator:



Dados da Primavera:



GORM:



O JDBC do Predator usa apenas 15 quadros até o momento em que sua solicitação é executada, enquanto o JPA do Predator usa 30 (principalmente por causa do Hibernate), em comparação com mais de 50 quadros de pilha no Spring Data ou GORM. E tudo graças aos mecanismos AOP do Micronaut que não usam reflexão.


Stackraces mais curtos também simplificam a depuração de aplicativos. Uma das vantagens de fazer a maior parte do trabalho durante a compilação é que erros podem ser detectados antes do lançamento do aplicativo, o que melhora muito a experiência do desenvolvedor. Obtemos erros de compilação imediatamente, em vez de erros de tempo de execução, para os erros mais comuns.


Verificações de tempo de compilação


A maioria das implementações do modelo de repositório depende apenas da execução de todas as operações em tempo de execução. Isso significa que, se o desenvolvedor cometer um erro ao definir a interface do repositório, os erros não serão visíveis até que o aplicativo seja realmente iniciado.


Isso nos tira alguns dos benefícios do Java para verificação de tipo e temos pouca experiência em dados. Este não é o caso do Predator. Considere o seguinte exemplo:


 @JdbcRepository(dialect = Dialect.H2) public interface BookRepository extends CrudRepository<Book, Long> { Book findByTile(String t); } 

Aqui BookRepository , declaramos uma solicitação para um objeto chamado Book , que possui uma propriedade title . Infelizmente, há um erro nesta declaração: findByTile método findByTile vez de findByTitle . Em vez de executar esse código, o Predator não permitirá que seu código seja compilado com uma mensagem de erro informativa:


 Error:(9, 10) java: Unable to implement Repository method: BookRepository.findByTile(String title). Cannot use [Equals] criterion on non-existent property path: tile 

Muitos aspectos do Predator são verificados no momento da compilação, quando possível, para garantir que um erro de tempo de execução não seja causado por uma declaração incorreta do repositório.


JDBC Predator e Substrato GraalVM


Outro motivo pelo qual o Predator deve ficar feliz é que ele é compatível com as imagens nativas do GraalVM Substrate e não requer conversões complexas de bytecode durante a compilação, ao contrário do Hibernate no GraalVM.


Ao eliminar completamente a reflexão e os proxies dinâmicos da camada de acesso a dados, o Predator simplifica bastante a criação de aplicativos que funcionam com dados em execução no GraalVM.


O aplicativo de amostra Predator JDBC é executado no Substrate sem problemas e permite criar uma imagem nativa muito menor (25 MB a menos!) Do que o Hibernate precisa para trabalhar, graças a uma camada de tempo de execução muito mais fina.


Vimos o mesmo resultado quando implementamos a compilação de regras de Validação de Bean para o Micronaut 1.2. O tamanho da imagem nativa diminuiu 10 MB, assim que removemos a dependência do Hibernate Validator e o tamanho JAR em 2 MB.


A vantagem aqui é óbvia: ao fazer mais trabalho durante a compilação e criar tempos de execução mais compactos, você obtém uma imagem nativa menor e um arquivo JAR, o que leva a menores e mais fáceis de implantar microsserviços ao implantar pelo Docker. O futuro das estruturas Java são compiladores mais poderosos e tempos de execução menores e mais leves.


Predador e o futuro


Estamos apenas começando a trabalhar com o Predator e estamos extremamente satisfeitos com as oportunidades que ele abre.


Inicialmente, começamos com suporte para JPA e SQL, mas no futuro você pode esperar suporte para MongoDB, Neo4J, SQL Reativo e outros bancos de dados. Felizmente, esse trabalho é muito mais simples, porque a maioria do Predator é realmente baseada no código-fonte GORM, e podemos reutilizar a lógica GORM para Neo4J e a lógica GORM para MongoDB para liberar essas implementações mais rapidamente do que o esperado.


O Predator é o ponto culminante da combinação dos vários blocos de construção no Micronaut Core que tornaram possível implementá-lo, desde as APIs do AoT, que também são usadas para gerar documentação do Swagger, até o relativamente novo suporte à Introspecção de Bean, que permite analisar objetos em tempo de execução sem reflexão.


O Micronaut fornece blocos de construção para coisas incríveis. O Predator é uma dessas coisas, e estamos apenas começando a trabalhar em alguns dos recursos promissores do Micronaut 1.0.


ATUALIZAÇÃO: Após o anúncio chocante, o assassino do Spring Data foi renomeado como Micronaut Data: https://micronaut-projects.imtqy.com/micronaut-data/1.0.x/guide/

Source: https://habr.com/ru/post/pt460839/


All Articles