Resolución de conflictos basada en marcas de tiempo en XDCR: la perspectiva de un QE

Introducción

Cross Datacenter Replication (XDCR) es una importante característica central de Couchbase que ayuda a los usuarios en la recuperación de desastres y la localización de datos. La resolución de conflictos es un reto inevitable al que se enfrenta XDCR cuando un documento se modifica en dos ubicaciones diferentes antes de que se haya sincronizado entre las ubicaciones.

Hasta 4.6, Couchbase sólo soportaba una estrategia basada en el ID de revisión para manejar la resolución de conflictos. En esta estrategia, el ID de revisión de un documento, que se actualiza cada vez que se modifica, se usa como primer campo para decidir el ganador. Si el ID de revisión de ambos contendientes es el mismo, entonces se utilizan CAS, TTL y flags en el mismo orden para resolver el conflicto. Esta estrategia funciona mejor para aplicaciones diseñadas para trabajar en base a una política de "la mayoría de las actualizaciones es mejor". Por ejemplo, una aplicación de ticker utilizada por conductores en un tren que actualiza un contador almacenado por el servidor cb para contar el número de pasajeros funcionará mejor con esta política y, por tanto, funcionará con precisión con la resolución de conflictos basada en el ID de revisión.

A partir de 4.6, Couchbase soportará una estrategia adicional llamada resolución de conflictos basada en timestamp. Aquí, la marca de tiempo de un documento que se almacena en CAS se utiliza como primer campo para decidir el ganador. Para mantener un orden consistente de las mutaciones, Couchbase utiliza un reloj lógico híbrido (HLC), que es una combinación de un reloj físico y un reloj lógico. Si la marca de tiempo de ambos contendientes es la misma, entonces el ID de revisión, el TTL y las banderas se usan en el mismo orden para resolver los conflictos. Esta estrategia se adapta para facilitar las aplicaciones que se diseñan basándose en una política de "la actualización más reciente es la mejor". Por ejemplo, una aplicación de seguimiento de vuelos que almacene la hora estimada de llegada de un vuelo en Couchbase Server funcionará correctamente con esta resolución de conflictos. Precisamente, este mecanismo puede resumirse como "La última escritura gana".

Hay que entender que el documento más actualizado no tiene por qué ser esencialmente el documento más reciente y viceversa. Así que el usuario realmente necesita entender el diseño, las necesidades y el patrón de datos de la aplicación antes de decidir qué mecanismo de resolución de conflictos utilizar. Por la misma razón, Couchbase ha diseñado el mecanismo de resolución de conflictos como un parámetro a nivel de bucket. Los usuarios deben decidir y seleccionar la estrategia que desean seguir al crear los buckets. Una vez creado un bucket con un mecanismo de resolución de conflictos concreto a través de UI, Rest API o CLI, no se puede cambiar. El usuario tendrá que eliminar y volver a crear el cubo para cambiar la estrategia. También para evitar confusiones y complicaciones, Couchbase ha restringido XDCR de ser configurado en modo mixto, es decir, cubos de origen y destino no pueden tener diferentes estrategias de resolución de conflictos seleccionados. Ambos tienen que usar la resolución de conflictos basada en el ID de revisión o en la marca de tiempo. Si el usuario intenta configurarlo de otro modo a través de la interfaz de usuario, Rest API o CLI, aparecerá un mensaje de error.

Resolución de conflictos basada en marcas de tiempo Casos prácticos

Alta disponibilidad con conmutación por error de clúster

Aquí, todas las operaciones de la base de datos van al Datacenter A y se replican vía XDCR al Datacenter B. Si el cluster localizado en el Datacenter A falla entonces la aplicación falla todo el tráfico al Datacenter B.

Localidad del centro de datos

Aquí, dos clusters activos operan sobre conjuntos discretos de documentos. Esto garantiza que no se generen conflictos durante el funcionamiento normal. Se configura una relación XDCR bidireccional para replicar sus actualizaciones entre sí. Cuando uno de los clústeres falla, el tráfico de la aplicación se puede transferir al clúster activo restante.

¿Cómo garantiza la resolución de conflictos basada en marcas de tiempo una conmutación por error segura?

La resolución de conflictos basada en marcas de tiempo requiere que las aplicaciones sólo permitan el tráfico hacia el otro Centro de Datos una vez transcurrido el máximo de los dos periodos de tiempo siguientes:

  1. La latencia de replicación entre A y B. Esto permite que cualquier mutación en vuelo sea recibida por el Datacenter B.
  2. El desvío de tiempo absoluto entre el Centro de Datos A y el Centro de Datos B. Esto garantiza que cualquier escritura en el Centro de Datos B se produzca después de la última escritura en el Centro de Datos A, tras el retraso calculado, momento en el que todas las operaciones de la base de datos irían al Centro de Datos B.

Cuando se restablece la disponibilidad del Centro de Datos A, las aplicaciones deben respetar el mismo periodo de tiempo antes de redirigir su tráfico. Para los dos casos de uso descritos anteriormente, el uso de la resolución de conflictos basada en marcas de tiempo garantiza que se conservará la versión más reciente de cualquier documento.

¿Cómo configurar NTP para la resolución de conflictos basada en marcas de tiempo?

Un requisito previo que los usuarios deben tener en cuenta antes de optar por la resolución de conflictos basada en marcas de tiempo es que necesitan utilizar relojes sincronizados para garantizar la precisión de esta estrategia. Couchbase les aconseja utilizar Network Time Protocol (NTP) para sincronizar la hora entre varios servidores. Los usuarios tendrán que configurar sus clusters para sincronizar periódicamente sus relojes de pared con un servidor NTP en particular o con un grupo de pares NTP para garantizar la disponibilidad. La sincronización de relojes es clave para la precisión del Reloj Lógico Híbrido utilizado por Couchbase para resolver conflictos basados en marcas de tiempo.

Como EQ, probar la resolución de conflictos basada en marcas de tiempo fue una buena experiencia de aprendizaje. Uno de los mayores retos fue aprender cómo funciona NTP. La configuración por defecto para todos los casos de prueba es activar NTP, iniciar el servicio, sincronizar el reloj de pared con 0.north-america.pool.ntp.org, y luego proceder con la prueba. Estos pasos se lograron utilizando los siguientes comandos en setup:

~$ chkconfig ntpd on

~$ /etc/init.d/ntpd start

~$ ntpdate -q 0.america-norte.pool.ntp.org

Una vez realizada la prueba y comprobados los resultados, se detiene y desactiva el servicio NTP mediante los siguientes comandos:

~$ chkconfig ntpd off

~$ /etc/init.d/ntpd stop

Esta es una configuración de vainilla donde todos los nodos individuales sincronizan su reloj de pared con 0.north-america.pool.ntp.org. Ha sido interesante automatizar casos de prueba en los que los nodos sincronizan su reloj de pared con un pool de pares NTP, el cluster origen y destino sincronizan con diferentes pools NTP (A (0.north-america.pool.ntp.org) -> B (3.north-america.pool.ntp.org)) y cada cluster en una topología en cadena de longitud 3 (A (EST) -> B (CST) -> C (PST)) están en diferentes zonas horarias. Tuvimos que configurar manualmente estos escenarios, observar el comportamiento y luego automatizarlo.

¿Cómo probamos los escenarios negativos basados en NTP?

El siguiente reto era probar escenarios en los que NTP no se ejecuta en los nodos Couchbase y hay una desviación horaria entre el origen y el destino. También puede ocurrir si la diferencia horaria entre los clusters es alta. Cualquier mecanismo de sincronización de tiempo tomará algún tiempo para sincronizar los relojes resultando en una ventana de tiempo sesgada. Ten en cuenta que Couchbase sólo avisa cuando se crea un bucket con resolución de conflictos basada en marcas de tiempo, indicando que el usuario debe asegurarse de que existe un mecanismo de sincronización de tiempo en todos los nodos. No valida ni restringe la creación de un bucket de este tipo si no existe un mecanismo de sincronización temporal. Por lo tanto, es muy posible que el usuario ignore esta advertencia, cree un cubo con resolución de conflictos basada en marcas de tiempo y observe un comportamiento extraño cuando se produzca un desajuste temporal.

Veamos una de estas situaciones:

  1. Creación de un bucket por defecto en los clústeres de origen y destino con resolución de conflictos basada en la fecha y hora
  2. Configurar XDCR de origen a destino
  3. Desactivar NTP en ambos clusters
  4. Hacer que el reloj de pared del clúster de destino sea 5 minutos más lento que el del clúster de origen.
  5. Pausar la replicación
  6. Crear un documento D1 en el momento T1 en el clúster de destino
  7. Crear un documento D2 con la misma clave en el momento T2 en el clúster de origen
  8. Actualizar D1 en el clúster de destino en el momento T3
  9. Reanudar la reproducción
  10. Obsérvese que D2 sobrescribe a D1 a pesar de que T1 > T2 > T3 y la última actualización de D1 en el cluster de destino debería haber ganado

En este caso, la última escritura por línea de tiempo no ganó, ya que los relojes estaban desviados y no sincronizados, lo que llevó a declarar ganador al doc incorrecto. Esto demuestra lo importante que es la sincronización temporal para la estrategia de resolución de conflictos basada en marcas de tiempo. Descifrar todos estos escenarios y automatizarlos ha sido todo un reto.

¿Cómo probamos escenarios complejos con la resolución de conflictos basada en marcas de tiempo?

Lo siguiente fue determinar una forma de validar la corrección de esta resolución de conflictos basada en la marca de tiempo frente a la estrategia basada en el ID de revisión. Necesitábamos realizar los mismos pasos en una configuración XDCR y verificar que los resultados eran diferentes en función de la estrategia de resolución de conflictos del bucket. Para conseguirlo, creamos dos cubos diferentes, uno configurado para utilizar la resolución de conflictos basada en el ID de revisión y otro para utilizar la basada en el sello de tiempo. Ahora siga estos pasos en ambos cubos paralelamente:

  1. Configurar XDCR y pausar la replicación
  2. Crear doc D1 en destino en el momento T1
  3. Crear doc D2 con la misma clave en origen en el momento T2
  4. Actualizar doc D2 en origen en el momento T3
  5. Actualizar doc D2 en la fuente de nuevo en el momento T4
  6. Actualizar doc D1 en el objetivo en el momento T5
  7. Reanudar la reproducción

En el primer cubo, que está configurado para utilizar la resolución de conflictos basada en revID, el documento D1 en el destino será sobrescrito por D2, ya que es el que más ha mutado. Mientras que en el segundo cubo, que está configurado para utilizar la resolución de conflictos basada en la marca de tiempo, el documento D1 en el destino será declarado ganador y conservado, ya que es el último en mutar. Descubrir estas situaciones y automatizarlas hizo que nuestra regresión fuera exhaustiva y robusta.

¿Cómo comprobamos la corrección del CLH?

El reto final era probar la monotonicidad del reloj lógico híbrido (HLC) utilizado por Couchbase en la resolución de conflictos basada en marcas de tiempo. Aparte de comprobar que el HLC seguía siendo el mismo entre un vbucket activo y su réplica, tuvimos algunos escenarios interesantes como los siguientes:

  1. C1 (más lento) -> C2 (más rápido) - las mutaciones realizadas en C1 perderán en función de la marca de tiempo y C2 siempre ganará - por lo que HLC de C2 no debería cambiar después de la replicación.
  2. C1 (más rápido) -> C2 (más lento) - las mutaciones realizadas en C1 siempre ganarán en función de la marca de tiempo - por lo que el HLC de C2 debería ser mayor que el de antes de la replicación debido a la monotonicidad
  3. Mismo escenario que 1, aunque el CLH de C2 no haya cambiado debido a la replicación, cualquier actualización en C2 debería aumentar su CLH debido a la monotonicidad.
  4. Del mismo modo, para el escenario descrito en 2, aparte de que el CLH de C2 sea mayor que antes de la replicación, más actualizaciones de los documentos en C2 deberían mantener su CLH en aumento debido a la monotonicidad.

Así pues, todos estos retos hicieron que probar la resolución de conflictos basada en marcas de tiempo fuera una gratificante hazaña de EQ.

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

Autor

Publicado por Arunkumar Senthilnathan, Ingeniero de software sénior, Couchbase

Arunkumar Senthilnathan es Ingeniero de Software Senior en Couchbase desde hace cuatro años. Arunkumar es responsable del desarrollo de la automatización de la interfaz de usuario mejorada para trabajar con la nueva interfaz de usuario angular.

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.