Algunas palabras sobre R2DBC y PostgreSQL

Recientemente, nuevamente veo que el bombo se ha intensificado en torno a la programación reactiva en general, y al trabajo reactivo con bases de datos en particular. Tengo un par de frases que me gustaría decir sobre esto.

imagen

Déjame recordarte lo que sucedió en series anteriores. A finales de 2017, salió Spring 5, que agregó soporte para programación reactiva. En particular, estamos hablando de WebFlux . Todos comenzaron a probar esta tecnología (una curva de bombo típica), y luego la industria se dio cuenta de que no todos necesitaban reactivismo. Lecciones clave aprendidas:

  • La programación reactiva es más difícil de depurar.
  • El desarrollo de sistemas reactivos es más difícil que los clásicos, bloqueantes; Si bloquea el hilo involuntariamente, habrá terminado. Por eso apareció el proyecto (uno de los autores -Bsideup )
  • La programación reactiva, y en particular la elasticidad, se necesita principalmente a altas cargas a la Netflix. Si tiene 100 RPS, probablemente debería escribir código en un estilo de bloqueo: es más barato y más fácil

Además, todos entendieron una cosa más. Para que la programación reactiva se desarrolle realmente, necesita que todo el sistema sea reactivo, incluida su base de datos. El problema es que la base de datos puede no tener una API reactiva, o al menos asincrónica. Bueno, o tal API puede ser, pero puede no ser compatible con su controlador.

En realidad, casi todos a mi alrededor están desarrollando sistemas PostgreSQL cuando necesito una base de datos relacional clásica. Dicho esto, la opción predeterminada. Trabajamos con PostgreSQL utilizando el antiguo controlador JDBC (más de 10 años) - pgjdbc . Este controlador es bueno para todos. Prácticamente no hay errores. Este controlador ha mejorado mucho en rendimiento (gracias por esto, incluyendovladimirsitnikov) Pero pgjdbc tiene un defecto fatal: no hay soporte para la API asincrónica .

En los últimos años, una gran carrera ha comenzado a desarrollar controladores alternativos para PostgreSQL, que incluyó el desarrollo de una API asincrónica. Incluso Oracle trató de hacer esto, pero ya cerró el desarrollo a favor del proyecto Loom y sus Fibras . Pero luego Oracle lo pensó mejor y comenzó a hacerlo nuevamente .

Hay 3 soluciones en este momento:

  1. https://github.com/jasync-sql/jasync-sql - controlador asíncrono para PostgreSQL, escrito en Kotlin, donde Netty es el transporte
  2. La solución que utiliza Vert.x es https://github.com/mauricio/postgresql-async . Es de destacar que el proyecto está archivado, y el controlador jasync-sql anterior reescribe de la misma manera (sin embargo, el original está escrito en Scala y la nueva solución en Kotlin).
    Actualizar Me corrigieron los comentarios, el cliente de Vert.x está vivo y se siente bien en los puntos de referencia .
  3. El controlador del equipo de Spring es https://github.com/r2dbc/r2dbc-postgresql . Este controlador proporciona inmediatamente una API reactiva (y no asíncrona), y Netty se usa para el transporte, como en jasync-sql.

Conceptualmente, estos controladores se basan en principios similares. Todos ellos usan características exclusivas de PostgreSQL:


Desafortunadamente, los controladores no pueden cambiar el protocolo Wire de Postgres (como si Oleg Dokuk no quisiera - https://www.youtube.com/watch?v=n9tL2I_Big8 ). Es decir, Postgres todavía requiere una conexión por separado para una consulta SELECT. Además, Postgres también está creando un nuevo proceso para cada conexión: https://www.postgresql.org/docs/current/tutorial-arch.html .

Sin embargo, hay buenas noticias. Las solicitudes de modificación se pueden enviar en lotes sin esperar el resultado (utilizando la canalización). Para este caso, no se requiere conexión para cada solicitud.

Es decir, para resumir. Los controladores PG reactivos (o asíncronos) mejoran la situación en las aplicaciones (ahora utilizamos IO sin bloqueo basado en Netty, no gastando hilos en una consulta), pero específicamente en el lado de PostgreSQL: las cosas no son tan buenas (esperemos una mejora en el protocolo de red y la arquitectura de la base de datos )

¿Qué controlador debería mirar más de cerca? Si, como yo, usa Spring en su trabajo, entonces r2dbc-postgresql es probablemente una buena opción. Es importante que en las últimas versiones de su marco, los chicos de Pivotal integraron bastante bien el controlador con las cosas habituales, por ejemplo, con Spring Data R2DBC(Esto sigue siendo RC). Como resultado, no tenemos que trabajar con una API de controlador de bajo nivel y el Pool de conexiones, lo que reduce la probabilidad de cometer un error en un proyecto tan complejo.

El ejemplo mínimo (que he espiado con éxito en la documentación) usando Spring Data R2DBC parece bastante familiar:

1. Configure las credenciales y el grupo de conexiones:

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. Crear una entidad:

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. Cree el repositorio habitual:

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

4. Use el repositorio:

@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);
    }
}

Puede encontrar un ejemplo completo en este repositorio: https://github.com/Hixon10/spring-boot-r2dbc-postgresql-example .

Finalmente, hablemos de lo importante: ¿necesita usar r2dbc ahora en sus aplicaciones? En mi opinión, es muy temprano. Esperaría a que se lanzara un conjunto de tecnologías (controlador, Spring DATA) y recogería las primeras tímidas. Creo que en 2021 ya será posible observar este controlador más de cerca.

El estado actual de las cosas: todo el sistema reactivo (controlador de base de datos Spring WebFlux + R2DBC) se ve muy bien. Literalmente hoyolegchirpublicó un resumen en el que hay un enlace a un artículo con puntos de referencia: https://technology.amis.nl/2020/04/10/spring-blocking-vs-non-blocking-r2dbc-vs-jdbc-and-webflux-vs- web-mvc / . En resumen: la reactividad gana.

All Articles