Cuándo usar una base de datos basada en CRDT

Roshan Kumar es gerente de producto senior en Redis Labs.

Doblar la consistencia y la disponibilidad como se describe en el teorema CAP ha sido un gran desafío para los arquitectos de las aplicaciones distribuidas geográficamente. La partición de red es inevitable. La alta latencia entre los centros de datos siempre da como resultado alguna desconexión entre los centros de datos durante un corto período de tiempo. Por lo tanto, las arquitecturas tradicionales para aplicaciones distribuidas geográficamente están diseñadas para renunciar a la coherencia de los datos o afectar la disponibilidad.

Desafortunadamente, no puede permitirse sacrificar la disponibilidad por aplicaciones de usuario interactivas. En los últimos tiempos, los arquitectos han probado la coherencia y han adoptado el modelo de coherencia eventual. En este modelo, las aplicaciones dependen del sistema de administración de la base de datos para fusionar todas las copias locales de los datos y hacerlas finalmente consistentes.

Todo se ve bien con el modelo de coherencia eventual hasta que haya conflictos de datos. Algunos modelos de consistencia eventual prometen el mejor esfuerzo para solucionar los conflictos, pero no garantizan una consistencia sólida. La buena noticia es que los modelos creados en torno a tipos de datos replicados sin conflictos (CRDT) ofrecen una gran coherencia eventual.

Los CRDT logran una fuerte consistencia eventual a través de un conjunto predeterminado de reglas y semánticas de resolución de conflictos. Las aplicaciones creadas sobre bases de datos basadas en CRDT deben diseñarse para adaptarse a la semántica de resolución de conflictos. En este artículo, exploraremos cómo diseñar, desarrollar y probar aplicaciones distribuidas geográficamente utilizando una base de datos basada en CRDT. También examinaremos cuatro ejemplos de casos de uso: contadores, almacenamiento en caché distribuido, sesiones compartidas e ingesta de datos de varias regiones.

Mi empleador, Redis Labs, anunció recientemente la compatibilidad con CRDT en Redis Enterprise, con tipos de datos replicados sin conflictos que se unen a la amplia cartera de estructuras de datos: cadenas, hashes, listas, conjuntos, conjuntos ordenados, campos de bits, geo, hiperloglog y transmisiones, en nuestro producto de base de datos. Sin embargo, la siguiente discusión se aplica no solo a Redis Enterprise, sino a todas las bases de datos basadas en CRDT.

Bases de datos para aplicaciones distribuidas geográficamente

Para las aplicaciones distribuidas geográficamente, es común ejecutar servicios locales para los clientes. Esto reduce el tráfico de la red y la latencia causada por el viaje de ida y vuelta. En muchos casos, los arquitectos diseñan los servicios para conectarse a una base de datos local. Luego viene la pregunta de cómo mantener datos consistentes en todas las bases de datos. Una opción es manejar esto a nivel de la aplicación; puede escribir un proceso de trabajo periódico que sincronizará todas las bases de datos. O puede confiar en una base de datos que sincronizará los datos entre las bases de datos.

Para el resto del artículo, asumimos que optará por la segunda opción: dejar que la base de datos haga el trabajo. Como se muestra en la Figura 1 a continuación, su aplicación distribuida geográficamente ejecuta servicios en varias regiones, y cada servicio se conecta a una base de datos local. El sistema de administración de base de datos subyacente sincroniza los datos entre las bases de datos implementadas en las regiones.

Laboratorios Redis

Modelos de coherencia de datos

Un modelo de coherencia es un contrato entre la base de datos distribuida y la aplicación que define qué tan limpios están los datos entre las operaciones de escritura y lectura.

Por ejemplo, en un modelo de coherencia fuerte, la base de datos garantiza que las aplicaciones siempre leerán la última escritura. Con coherencia secuencial, la base de datos asegura que el orden de los datos que lee sea coherente con el orden en que se escribieron en la base de datos. En el eventual modelo de coherencia, la base de datos distribuida promete sincronizar y consolidar los datos entre las réplicas de la base de datos entre bastidores. Por lo tanto, si escribe sus datos en una réplica de la base de datos y los lee de otra, es posible que no lea la última copia de los datos.

Consistencia fuerte

El compromiso de dos fases es una técnica común para lograr una gran coherencia. Aquí, para cada operación de escritura (agregar, actualizar, eliminar) en un nodo de la base de datos local, el nodo de la base de datos propaga los cambios a todos los nodos de la base de datos y espera a que todos los nodos los reconozcan. El nodo local envía una confirmación a todos los nodos y espera otro reconocimiento. La aplicación podrá leer los datos solo después de la segunda confirmación. La base de datos distribuida no estará disponible para operaciones de escritura cuando la red se desconecte entre las bases de datos.

Consistencia eventual

La principal ventaja del modelo de consistencia eventual es que la base de datos estará disponible para realizar operaciones de escritura incluso cuando la conectividad de red entre las réplicas de bases de datos distribuidas se rompa. En general, este modelo evita el tiempo de ida y vuelta incurrido por una confirmación de dos fases y, por lo tanto, admite muchas más operaciones de escritura por segundo que los otros modelos. Un problema que la coherencia eventual debe abordar son los conflictos: escrituras simultáneas en el mismo elemento en dos ubicaciones diferentes. Según cómo evitan o resuelven los conflictos, las bases de datos eventualmente consistentes se clasifican en las siguientes categorías:

  1. El último escritor gana (LWW).  En esta estrategia, las bases de datos distribuidas se basan en la sincronización de la marca de tiempo entre los servidores. Las bases de datos intercambian la marca de tiempo de cada operación de escritura junto con los datos en sí. En caso de conflicto, gana la operación de escritura con la última marca de tiempo.

    La desventaja de esta técnica es que asume que todos los relojes del sistema están sincronizados. En la práctica, es difícil y costoso sincronizar todos los relojes del sistema.

  2. Consistencia eventual basada en quórum: esta técnica es similar a la confirmación de dos fases. Sin embargo, la base de datos local no espera el reconocimiento de todas las bases de datos; solo espera el reconocimiento de la mayoría de las bases de datos. El reconocimiento de la mayoría establece quórum. En caso de conflicto, gana la operación de escritura que ha establecido el quórum.

    Por otro lado, esta técnica agrega latencia de red a las operaciones de escritura, lo que hace que la aplicación sea menos escalable. Además, la base de datos local no estará disponible para escrituras si se aísla de las otras réplicas de la base de datos en la topología.

  3. Replicación de fusión: en este enfoque tradicional, que es común entre las bases de datos relacionales, un agente de fusión centralizado fusiona todos los datos. Este método también ofrece cierta flexibilidad para implementar sus propias reglas para resolver conflictos.

    La replicación de fusiones es demasiado lenta para admitir aplicaciones atractivas en tiempo real. También tiene un solo punto de falla. Como este método no admite reglas preestablecidas para la resolución de conflictos, a menudo conduce a implementaciones con errores para la resolución de conflictos.

  4. Tipo de datos replicados sin conflictos (CRDT): aprenderá sobre los CRDT en detalle en las siguientes secciones. En pocas palabras, las bases de datos basadas en CRDT admiten tipos de datos y operaciones que brindan una consistencia eventual sin conflictos. Las bases de datos basadas en CRDT están disponibles incluso cuando las réplicas de bases de datos distribuidas no pueden intercambiar los datos. Siempre entregan latencia local a las operaciones de lectura y escritura.

    Limitaciones No todos los casos de uso de bases de datos se benefician de los CRDT. Además, la semántica de resolución de conflictos para las bases de datos basadas en CRDT está predefinida y no se puede anular.

¿Qué son los CRDT?

Los CRDT son tipos de datos especiales que convergen datos de todas las réplicas de bases de datos. Los CRDT populares son contadores G (contadores solo de crecimiento), contadores PN (contadores positivos-negativos), registros, conjuntos G (conjuntos solo de crecimiento), conjuntos 2P (conjuntos de dos fases), conjuntos OR ( conjuntos observados-eliminados), etc.Detrás de escena, se basan en las siguientes propiedades matemáticas para hacer converger los datos:

  1. Propiedad conmutativa: a ☆ b = b ☆ a
  2. Propiedad asociativa: a ☆ (b ☆ c) = (a ☆ b) ☆ c
  3. Idempotencia:  a ☆ a = a

Un contador G es un ejemplo perfecto de un CRDT operativo que fusiona las operaciones. Aquí, a + b = b + a y a + (b + c) = (a + b) + c. Las réplicas intercambian solo las actualizaciones (adiciones) entre sí. El CRDT fusionará las actualizaciones agregándolas. Un G-set, por ejemplo, aplica idempotencia ({a, b, c} U {c} = {a, b, c}) para fusionar todos los elementos. Idempotence evita la duplicación de elementos agregados a una estructura de datos a medida que viajan y convergen a través de diferentes caminos.

Tipos de datos CRDT y su semántica de resolución de conflictos

Estructuras de datos libres de conflictos: contadores G, contadores PN, conjuntos G

Todas estas estructuras de datos están libres de conflictos por diseño. Las tablas siguientes muestran cómo se sincronizan los datos entre las réplicas de la base de datos.

Redis Labs Redis Labs

Los contadores G y los contadores PN son populares para casos de uso como sondeo global, recuentos de transmisiones, seguimiento de actividad, etc. Los G-sets se utilizan mucho para implementar la tecnología blockchain. Los bitcoins, por ejemplo, emplean entradas de cadena de bloques solo para agregar.

Registros: cadenas, hashes

Los registros no están libres de conflictos por naturaleza. Por lo general, siguen las políticas de LWW o resolución de conflictos basada en quórum. La Figura 4 muestra un ejemplo de cómo un registro resuelve el conflicto siguiendo la política de LWW.

Laboratorios Redis

Los registros se utilizan principalmente para almacenar datos de sesión y almacenamiento en caché, información de perfil de usuario, catálogo de productos, etc.

Juegos 2P

Los conjuntos de dos fases mantienen dos conjuntos de conjuntos G: uno para elementos añadidos y el otro para elementos eliminados. Las réplicas intercambian las adiciones del G-set cuando se sincronizan. El conflicto surge cuando se encuentra el mismo elemento en ambos conjuntos. En algunas bases de datos basadas en CRDT, como Redis Enterprise, esto se maneja mediante la política "Agregar gana sobre la eliminación".

Laboratorios Redis

El 2P-set es una buena estructura de datos para almacenar datos de sesión compartidos, como carritos de compras, un documento compartido o una hoja de cálculo.

Cómo diseñar una aplicación para usar una base de datos basada en CRDT

Conectar su aplicación a una base de datos basada en CRDT no es diferente de conectar su aplicación a cualquier otra base de datos. Sin embargo, debido a las eventuales políticas de coherencia, su aplicación debe seguir un determinado conjunto de reglas para ofrecer una experiencia de usuario coherente. Tres claves: 

  1. Haga su solicitud sin estado. Una aplicación sin estado suele estar impulsada por API. Cada llamada a una API da como resultado la reconstrucción del mensaje completo desde cero. Esto garantiza que siempre obtenga una copia limpia de los datos en cualquier momento. La baja latencia local que ofrece una base de datos basada en CRDT hace que la reconstrucción de mensajes sea más rápida y sencilla. 

  2. Seleccione el CRDT adecuado que se adapte a su caso de uso. El contador es el más simple de los CRDT. Se puede aplicar para casos de uso como votación global, seguimiento de sesiones activas, medición, etc. Sin embargo, si desea fusionar el estado de los objetos distribuidos, también debe considerar otras estructuras de datos. Por ejemplo, para una aplicación que permite a los usuarios editar un documento compartido, es posible que desee conservar no solo las ediciones, sino también el orden en que se realizaron. En ese caso, guardar las ediciones en una lista basada en CRDT o en una estructura de datos de cola sería una mejor solución que almacenarlas en un registro. También es importante que comprenda la semántica de resolución de conflictos impuesta por los CRDT y que su solución se ajuste a las reglas.
  3. CRDT no es una solución única para todos. Si bien CRDT es de hecho una gran herramienta para muchos casos de uso, puede que no sea la mejor para todos los casos de uso (transacciones ACID, por ejemplo). Las bases de datos basadas en CRDT generalmente se ajustan bien a la arquitectura de microservicios, donde tiene una base de datos dedicada para cada microservicio.

La conclusión principal aquí es que su aplicación debe centrarse en la lógica y delegar la gestión de datos y la complejidad de la sincronización a la base de datos subyacente.

Prueba de aplicaciones con una base de datos multimaestro distribuida

Para lograr una salida al mercado más rápida, le recomendamos que tenga un desarrollo, pruebas, preparación y configuración de producción consistentes. Entre otras cosas, eso significa que su configuración de desarrollo y prueba debe tener un modelo miniaturizado de su base de datos distribuida. Compruebe si su base de datos basada en CRDT está disponible como contenedor Docker o dispositivo virtual. Implemente las réplicas de su base de datos en diferentes subredes para que pueda simular la configuración del clúster conectado y desconectado.

Probar aplicaciones con una base de datos multimaestro distribuida puede parecer complejo. Pero la mayoría de las veces, lo único que probará es la coherencia de los datos y la disponibilidad de la aplicación en dos situaciones: cuando las bases de datos distribuidas están conectadas y cuando hay una partición de red entre las bases de datos.

Al configurar una base de datos distribuida de tres nodos en su entorno de desarrollo, puede cubrir (e incluso automatizar) la mayoría de los escenarios de prueba en las pruebas unitarias. Estas son las pautas básicas para probar sus aplicaciones: