Algumas palavras sobre R2DBC e PostgreSQL

Recentemente, vejo novamente que o hype se intensificou em torno da programação reativa em geral e do trabalho reativo com bancos de dados em particular. Eu tenho algumas frases que gostaria de dizer sobre isso.

imagem

Deixe-me lembrá-lo do que aconteceu nas séries anteriores. No final de 2017, foi lançada a primavera 5, na qual apareceu o suporte à programação reativa. Em particular, estamos falando sobre o WebFlux . Todos começaram a experimentar fortemente essa tecnologia (uma típica curva de hype) e, em seguida, a indústria percebeu que nem todos precisavam de reativismo. Principais lições aprendidas:

  • A programação reativa é mais difícil de depurar
  • Desenvolver sistemas reativos é mais difícil que os clássicos, bloqueadores; se você bloquear inadvertidamente o encadeamento, estará concluído. É por isso que o projeto apareceu (um dos autores -bsideup )
  • A programação reativa e, em particular, a elasticidade, são necessárias principalmente em altas cargas no Netflix. Se você possui 100 RPS, provavelmente deve escrever código em um estilo de bloqueio - é mais barato e mais fácil

Além disso, todos entenderam mais uma coisa. Para que a programação reativa realmente se desdobre, você precisa que todo o sistema seja reativo, incluindo seu banco de dados. O problema é que o banco de dados pode nem ter uma API reativa ou pelo menos assíncrona. Bem, ou tal API pode ser, mas pode não ser suportada no seu driver.

Na verdade, quase todo mundo ao meu redor está desenvolvendo sistemas PostgreSQL quando preciso de um banco de dados relacional clássico. Dito isto, a escolha padrão. Trabalhamos com o PostgreSQL usando o driver JDBC antigo (acima de 10 anos) - pgjdbc . Este driver é bom para todos. Praticamente não há bugs. Esse driver é bastante aprimorado em desempenho (obrigado por isso, incluindovladimirsitnikov) Mas o pgjdbc tem uma falha fatal - não há suporte para a API assíncrona .

Nos últimos anos, uma grande corrida começou a desenvolver drivers alternativos para o PostgreSQL, que incluíam o desenvolvimento de uma API assíncrona. Até a Oracle tentou fazer isso, mas já encerrou o desenvolvimento em favor do projeto Loom e de suas fibras . Mas então a Oracle pensou melhor e começou a fazê-lo novamente .

Existem 3 soluções agora:

  1. https://github.com/jasync-sql/jasync-sql - driver assíncrono para PostgreSQL, escrito em Kotlin, onde Netty é o transporte
  2. A solução usada pelo Vert.x é https://github.com/mauricio/postgresql-async . Vale ressaltar que o projeto foi arquivado e o driver jasync-sql anterior reescreve da mesma forma (no entanto, o original está escrito em Scala e a nova solução em Kotlin).
    Atualizar Fui corrigido nos comentários, o cliente do Vert.x está vivo e se sente bem nos benchmarks .
  3. O driver da equipe do Spring é https://github.com/r2dbc/r2dbc-postgresql . Esse driver fornece imediatamente uma API reativa (e não assíncrona) e o Netty é usado para transporte, como no jasync-sql.

Conceitualmente, esses drivers são construídos com princípios semelhantes. Todos eles usam exclusivamente recursos existentes do PostgreSQL:


Infelizmente, os drivers não podem alterar o Postgres do protocolo Wire (como se Oleg Dokuk não quisesse - https://www.youtube.com/watch?v=n9tL2I_Big8 ). Ou seja, o Postgres ainda requer uma conexão separada para uma consulta SELECT. Além disso, o Postgres também está criando um novo processo para cada conexão - https://www.postgresql.org/docs/current/tutorial-arch.html .

No entanto, há boas notícias. As solicitações de modificação podem ser enviadas em lotes sem aguardar o resultado (usando o pipeline). Nesse caso, a conexão não é necessária para cada solicitação.

Ou seja, para resumir. Drivers PG reativos (ou assíncronos) melhoram a situação nos aplicativos (agora usamos IO sem bloqueio baseado em Netty, sem desperdiçar threads em uma solicitação), mas especificamente no lado do PostgreSQL - as coisas não são tão boas (esperemos uma melhoria no protocolo de rede e na arquitetura do banco de dados )

Qual driver você deve olhar mais de perto? Se você, como eu, usa o Spring no seu trabalho, o r2dbc-postgresql provavelmente é uma boa escolha. É importante que, nas versões mais recentes de sua estrutura, os caras da Pivotal integrem bastante bem o driver às coisas usuais, por exemplo, com o Spring Data R2DBC(ainda é RC). Como resultado, não precisamos trabalhar com a API de driver de baixo nível e o Pool de conexões, o que reduz a probabilidade de cometer um erro em um projeto tão complexo.

O exemplo mínimo (que eu espiei com sucesso na documentação) usando o Spring Data R2DBC parece bastante familiar:

1. Configure credenciais e pool de conexão:

spring.r2dbc.username=postgres
spring.r2dbc.password=P4$$W0RddD
spring.r2dbc.url=r2dbc:postgresql://localhost:5432/r2dbc
spring.r2dbc.pool.enabled=true
spring.r2dbc.pool.initial-size=10
spring.r2dbc.pool.max-idle-time=1m
spring.r2dbc.pool.max-size=30
spring.data.r2dbc.repositories.enabled=true

2. Crie uma entidade:

public class Customer {
    @Id
    private Long id;

    private String firstName;

    private String lastName;

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

3. Crie o Repositório usual:

public interface CustomerRepository extends ReactiveCrudRepository<Customer, Long> {
}

4. Use o repositório:

@RestController
@RequestMapping("/")
public class CustomerController {

    private CustomerRepository customerRepository;

    @PostMapping("/customer")
    Mono<Void> create(@RequestBody Publisher<Customer> customerFlux) {
        return customerRepository.saveAll(customerFlux).then();
    }

    @GetMapping("/customer")
    public Flux<Customer> list() {
        return customerRepository.findAll();
    }

    @GetMapping("/customer/{id}")
    public Mono<Customer> findById(@PathVariable Long id) {
        return customerRepository.findById(id);
    }
}

Um exemplo completo pode ser encontrado neste repositório - https://github.com/Hixon10/spring-boot-r2dbc-postgresql-example .

Finalmente, vamos falar sobre o importante: você precisa usar o r2dbc agora em seus aplicativos? Na minha opinião, é muito cedo. Eu esperaria que um conjunto de tecnologias (driver, Spring DATA) fosse lançado e coletasse os primeiros shys. Eu acho que em 2021 já será possível olhar para esse driver mais de perto.

O estado atual das coisas - todo o sistema reativo (driver de banco de dados Spring WebFlux + R2DBC) parece muito legal. Hoje literalmenteolegchirpublicou um resumo no qual há um link para um artigo com referências - https://technology.amis.nl/2020/04/10/spring-blocking-vs-non-blocking-r2dbc-vs-jdbc-and-webflux-vs- web-mvc / . Em resumo - a reatividade vence.

All Articles