Sin categoría

Por qué debe preocuparle el acceso reactivo a bases de datos

Desde que anunciamos que nuestro nuevo SDK de Java se basa por completo en componentes reactivos y asíncronos, nuestros usuarios no dejan de preguntarnos cuáles son las ventajas con respecto a sus patrones de acceso síncronos de toda la vida. Aunque muy a menudo el "rendimiento" es uno de los factores determinantes, hay mucho más a tener en cuenta. Además de la gestión de errores (que se tratará en otro artículo), destacan las siguientes características:

  1. Construir flujos de datos con flujos de datos
  2. Mejor aprovechamiento de los recursos sin quebraderos de cabeza

El propósito de esta entrada de blog es convertir patrones comunes de acceso a datos de síncronos a reactivos y, como resultado, darte una idea de lo que es posible con este nuevo enfoque. No te preocupes si nunca has escrito código "reactivo" - aprenderás algunas nociones básicas por el camino. Además, ten en cuenta que seguimos soportando una API síncrona. La API síncrona es sólo una fina envoltura alrededor de la reactiva, lo que le permite migrar gradualmente su aplicación a un enfoque más potente, sin tener que saltar en el extremo profundo de inmediato.

Ah, y por cierto, tenemos un Próximo seminario web el 22 de enero, Simon Basle, uno de nuestros ingenieros del SDK, presentará el nuevo SDK de Java y mostrará algunas de las partes reactivas. Únete a él y hazle preguntas.

El patrón de búsqueda

Un patrón muy común cuando se accede a una base de datos o a un almacén de claves/valores es el patrón de búsqueda. Se carga un documento y, en función de su contenido, se cargan más documentos. Consideremos el ejemplo clásico de "entrada de blog y comentarios". Imagina que tienes la siguiente entrada de blog almacenada en Couchbase:

Contiene una lista de identificadores de comentarios que puede utilizarse para cargar los detalles completos de cada contenido según sea necesario. Un comentario puede tener este aspecto

Ahora digamos que queremos cargar los dos primeros comentarios que se publican cuando se carga la entrada del blog, para que se muestren debajo de la publicación real. Aquí hay una manera de lograr esto con el acceso síncrono y el nuevo SDK:

Dejando a un lado la gestión de errores, este enfoque tiene algunos inconvenientes:

  • Tenemos que esperar al menos 3 veces a que la red responda, manteniendo nuestro hilo inactivo mientras que potencialmente podría realizar un trabajo valioso en su lugar.
  • Es muy difícil aplicar un tiempo de espera global a todo el proceso, ya que cada operación tiene un tiempo de espera individual.

 

Vamos a convertir esto en un enfoque reactivo, también utilizando Java 8 lambdas (Java 6/7 también son compatibles, sólo tiene que utilizar clases anónimas en lugar de callbacks):

Basándonos en el nombre de los operadores, está bastante claro lo que está pasando. El código carga la entrada del blog. Una vez que llega, extrae la lista de IDs de comentarios y la pasa al siguiente método que carga realmente los documentos de comentarios. El método de filtrado sólo deja pasar los comentarios que están publicados. Después, sólo tomamos los 2 primeros comentarios y nos damos de baja para evitar más trabajo (como cargar más documentos, cuando ya tenemos suficientes). Finalmente, agregamos todos los comentarios encontrados en una lista, aplicamos un tiempo de espera global y luego bloqueamos.

Este código se "despliega" para cargar todos los comentarios necesarios en paralelo, llegando a más nodos del clúster al mismo tiempo y, como resultado, devolviendo los resultados deseados más rápidamente. Además, el código aplica un tiempo de espera global a toda la "operación", algo muy difícil de conseguir con código síncrono. Por último, todo el código es componible. Puedes encapsular la lógica en un método sin aplicar un tiempo de espera o especificar cuántos comentarios "tomar". La capa superior puede entonces encadenar los operadores que necesite para realizar el trabajo como desee.

Además, puedes ver que es muy fácil pasar del concepto más potente (async, reactivo) al menos potente (sync). Al revés no es posible.

Tenga en cuenta que seguimos bloqueando al final, y eso está bien. La mayoría de las aplicaciones se bloquearán en algún momento (quizás incluso justo antes de devolver una respuesta al usuario). Aunque ser "reactivo" en toda la pila te da el mejor rendimiento y utilización de recursos, puedes hacer que grandes partes de tu código se ejecuten de forma asíncrona y beneficiarte enormemente.

Ejecución de consultas

Naturalmente, toda base de datos permite consultar sus documentos almacenados en función de determinados criterios. La mayoría de las veces, se devolverá más de un registro, a veces incluso miles en un solo lote. Una vez obtenidos los datos, a menudo es necesario modificar, combinar o filtrar el contenido en función de los requisitos de la aplicación.

Consideremos el siguiente ejemplo: usted es un proveedor de telecomunicaciones y almacena registros de usuarios en su cubo. A final de mes quiere asegurarse de que todos los nuevos clientes que se han dado de alta este mes han recibido realmente su nuevo teléfono. Su empresa de paquetería contratada ofrece un servicio web en el que puede consultar el estado de la entrega.

Esta es la implementación simulada del proveedor:

Dado un UUID que representa el ID del paquete, devolvemos aleatoriamente si un paquete ya ha sido entregado o no.

Este es el aspecto que podría tener un registro de usuario:

Usamos N1QL para obtener todos los usuarios del último mes y luego pasamos el ID del paquete a nuestro proveedor. Aquí está la versión sincrónica:

Este código no parece tan malo, ¿verdad? ¿Y si te digo que tu proveedor de paquetes tiene un servidor web increíblemente malo que a veces devuelve las consultas en 10 segundos en lugar de en 500 milisegundos? Además, perdemos la posibilidad de transmitir nuestros resultados y realizar acciones justo cuando llegan.

Imaginemos que hemos tenido suerte y se han registrado 2000 nuevos clientes. Primero tenemos que esperar a que los 2000 usuarios sean consultados y luego tenemos que realizar 2000 consultas en serie contra el servidor web de nuestro proveedor de paquetes. Por supuesto, podemos enviarlas a un servicio ejecutor, pero entonces tendremos que realizar la orquestación y la agregación por nuestra cuenta.

Podemos hacerlo mucho mejor con la versión reactiva:

Aquí, estamos transmitiendo los resultados a medida que llegan desde el servidor. Una vez que tenemos un resultado, extraemos el ID del paquete y lo enviamos al servidor de paquetes. Una vez que llega una respuesta, la tomamos y la agrupamos por el estado de envío. Por último, aplicamos un buen formato y lo imprimimos. Como nunca bloqueamos, enviamos todas las solicitudes al servidor de paquetes y las agrupamos una vez que vuelven (en cualquier orden). Si algunas de las peticiones tardan más, no nos importa realmente porque podemos terminar de procesar las otras primero y no estamos atascados. También podemos aplicar un tiempo de espera global.

Resumen

Estos dos ejemplos muestran claramente cómo su aplicación puede beneficiarse hoy de la ejecución asíncrona y reactiva. Proporciona un camino claro para alejarse de los controladores de bases de datos bloqueantes y acaparadores de recursos que ralentizan sus servidores de aplicaciones y sus tiempos de respuesta.

Apenas hemos arañado la superficie de lo que es posible. Estamos trabajando en proyectos de ejemplo y documentación ampliada para ofrecerte una guía clara en esta nueva forma de escribir aplicaciones de acceso a bases de datos. Háganos saber si desea ver su caso de uso cubierto y / o cómo se puede transformar.

Por último, de nuevo un rápido recordatorio de que dentro de unos días habrá un seminario web sobre el nuevo SDK de Java. ¡Únete, escucha la introducción y luego no dudes en hacer tus preguntas!

Comparte este artículo
Recibe actualizaciones del blog de Couchbase en tu bandeja de entrada
Este campo es obligatorio.

Author

Posted by Michael Nitschinger, Principal Software Engineer, Couchbase

Michael Nitschinger trabaja como Ingeniero de Software Principal en Couchbase. Es el arquitecto y mantenedor del SDK Java de Couchbase, uno de los primeros controladores de bases de datos completamente reactivos en la JVM. También es autor y mantiene el conector Spark de Couchbase. Michael participa activamente en la comunidad de código abierto, contribuyendo a otros proyectos como RxJava y Netty.

1 Comentarios

  1. Jacek Laskowski marzo 10, 2015 a 8:23 pm

    Una entrada de blog muy útil. Me gustaría que hubiera más acerca de cómo los respectivos métodos están haciendo bajo las cubiertas para que todo el flujo de datos es asíncrono y no de bloqueo. ¿Cómo es que una vez que llega una fila/registro pasa a la siguiente llamada de método? Apenas puedo imaginarlo, y de ahí las preguntas sobre las interioridades del SDK.

Deja un comentario

¿Listo para empezar con Couchbase Capella?

Empezar a construir

Consulte nuestro portal para desarrolladores para explorar NoSQL, buscar recursos y empezar con tutoriales.

Utilizar Capella gratis

Ponte manos a la obra con Couchbase en unos pocos clics. Capella DBaaS es la forma más fácil y rápida de empezar.

Póngase en contacto

¿Quieres saber más sobre las ofertas de Couchbase? Permítanos ayudarle.