Este artículo es un artículo espejo de traducción automática, por favor haga clic aquí para saltar al artículo original.

Vista: 10939|Respuesta: 1

Varias formas de usar cerraduras distribuidas (redis, zookeeper, base de datos)

[Copiar enlace]
Publicado en 30/8/2018 15:04:32 | | | |
P: Un servidor de servicio, una base de datos, operación: consulta el saldo actual del usuario, deduce el 3% del saldo actual como tarifa de gestión

sincronizado
cerradura
Bloqueo de bases de datos

P: Dos servidores de servicio, una base de datos, operación: consulta el saldo actual del usuario, deduce el 3% del saldo actual como tarifa de gestión
Bloqueos distribuidos

¿Qué tipo de cerradura distribuida necesitamos?
Puede garantizar que en un clúster de aplicaciones distribuido, el mismo método solo pueda ejecutarse por un hilo en una máquina al mismo tiempo.

Si esta esclusa es una esclusa reentrante (evitar los bloqueos)

Esta cerradura es mejor para ser una cerradura bloqueadora (considera si la quieres según las necesidades de tu negocio)

Esta cerradura es mejor para ser justa (considera si quieres esta o no según las necesidades del negocio).

Existen funciones de adquisición y liberación de bloqueo altamente disponibles

El rendimiento de los seguros de adquisición y liberación es mejor

1. Bloqueos distribuidos basados en bases de datos

Bloqueos distribuidos basados en implementaciones basadas en tablas

Cuando queremos bloquear un método, ejecutamos el siguiente SQL:
insertar en methodLock(method_name,desc) valores ('method_name','desc')
Debido a que hemos establecido una restricción de unicidad en el method_name, si se envían múltiples solicitudes a la base de datos al mismo tiempo, esta asegurará que solo una operación pueda tener éxito, entonces podemos asumir que el hilo que obtuvo con éxito el bloqueo del método y puede ejecutar el contenido del cuerpo del método.

Cuando se ejecuta el método, si quieres liberar el bloqueo, necesitas ejecutar el siguiente SQL:
eliminar desde methodLock donde method_name ='method_name'

Esta simple implementación anterior presenta los siguientes problemas:

  • Este bloqueo depende de la disponibilidad de la base de datos, que es un punto único y hará que el sistema empresarial no esté disponible una vez que la base de datos se cuelgue.
  • Este bloqueo no tiene tiempo de caducidad y, una vez que la operación de desbloqueo falla, el registro del bloqueo permanecerá en la base de datos y otros hilos ya no podrán obtener el bloqueo.
  • Este bloqueo solo puede ser no bloqueante, porque la operación de inserción de datos informará directamente de un error una vez que la inserción falle. Los hilos que no adquieren bloqueos no entrarán en la cola y deberán activar de nuevo la operación de adquisición de bloqueo para obtener el bloqueo de nuevo.
  • El candado no es reentrante, y el mismo hilo no puede volver a obtener el candado hasta que se libera. Porque los datos en los datos ya existen.
  • Esta cerradura es injusta, y todos los hilos que esperan la cerradura compiten por la suerte.


Por supuesto, también podemos resolver los problemas anteriores de otras maneras.

  • ¿La base de datos es un punto único? Construye dos bases de datos y los datos se sincronizarán en ambas direcciones. Una vez colgado, cambia rápidamente a la biblioteca de respaldo.
  • ¿No hay tiempo de caducidad? Simplemente haz una tarea programada para limpiar los datos de tiempo de espera en la base de datos a intervalos regulares.
  • ¿No bloqueante? Haz un bucle de tiempo hasta que el inserto tenga éxito y luego devuelva el éxito.
  • ¿No reentrante? Añade un campo a la tabla de la base de datos para registrar la información del host y la información del hilo de la máquina que actualmente recibe el bloqueo, y la próxima vez que consigas el bloqueo, consulta primero la base de datos; si la información del host y la información del hilo de la máquina actual se encuentran en la base de datos, puedes asignarle directamente el bloqueo.
  • ¿Injusto? Crea otra tabla intermedia para registrar todos los hilos que esperan el bloqueo, y ordénalos según el tiempo de creación, y solo el primero creado puede adquirir el bloqueo


Bloqueos distribuidos basados en bloqueos exclusivos

Además de añadir y eliminar registros en la tabla de datos, los bloqueos distribuidos también pueden implementarse con la ayuda de los bloqueos que vienen con los datos.

También usamos la tabla de base de datos que acabamos de crear. Los bloqueos distribuidos pueden implementarse mediante bloqueos exclusivos en bases de datos. El motor InnoDB basado en MySQL puede utilizar los siguientes métodos para implementar operaciones de bloqueo:

Si añades para actualización después de la sentencia de consulta, la base de datos añadirá un bloqueo exclusivo a la tabla durante el proceso de consulta. Cuando se añade un bloqueo exclusivo a un registro, otros hilos ya no pueden añadir un bloqueo exclusivo al registro en esa línea.

Podemos pensar que el hilo que obtiene el bloqueo exclusivo puede obtener el bloqueo distribuido, y cuando se obtiene el bloqueo, la lógica de negocio del método puede ejecutarse y luego desbloquearse mediante los siguientes métodos:

desbloqueo de vacío público(){ connection.commit(); }

a través de connection.commit(); operación para abrir la cerradura.

Este método puede resolver eficazmente los problemas mencionados anteriormente sobre la imposibilidad de abrir y bloquear el candado.

¿Bloquear cerraduras? La instrucción for update regresa inmediatamente después de la ejecución exitosa y permanece bloqueada hasta que tiene éxito.

¿El servicio se ha caído después del bloqueo, no se puede liberar? De este modo, la base de datos libera el bloqueo por sí sola después de que el servicio se cae.

Sin embargo, aún no resuelve directamente el problema de punto único de base de datos, reentrancia y bloqueo justo.

Para resumir la forma de usar la base de datos para implementar bloqueos distribuidos, ambos basados en una tabla dentro de la base de datos, uno es determinar si existe un bloqueo por la existencia de registros en la tabla, y el otro es implementar bloqueos distribuidos mediante el bloqueo exclusivo de la base de datos.

Ventajas de las bases de datos de bloqueo distribuidas

Directamente con la ayuda de la base de datos, es fácil de entender.

Desventajas de implementar bloqueos distribuidos en bases de datos

Habrá varios problemas, y la solución completa se volverá cada vez más compleja en el proceso de resolverlo.

Operar la base de datos requiere cierta sobrecarga y es necesario considerar los problemas de rendimiento.

2. Bloqueos distribuidos basados en caché

En comparación con la solución de bloqueo distribuido basada en bases de datos, la implementación basada en caché tendrá un mejor rendimiento en cuanto a rendimiento.

Actualmente hay muchos productos de caché maduros, incluyendo Redis, memcached, etc. Aquí tomamos Redis como ejemplo para analizar el esquema de usar caché para implementar bloqueos distribuidos.

Hay muchos artículos relacionados en Internet sobre cómo implementar bloqueos distribuidos basados en Redis, y el método principal de implementación es utilizar el método Jedis.setNX.

También existen varios problemas con la implementación anterior:

1. Problema de un solo punto.

2. Este bloqueo no tiene tiempo de expiración; una vez que la operación de desbloqueo falla, el registro del bloqueo estará en redis todo el tiempo y otros hilos ya no podrán obtener el bloqueo.

3. Este bloqueo solo puede ser no bloqueante, y volverá directamente independientemente de si tenga éxito o fracaso.

4. Este candado no es reentrante; después de que un hilo obtiene el candado, no puede volver a obtener el candado antes de soltarlo, porque la llave utilizada ya existe en redis. las operaciones setNX ya no pueden ejecutarse.

5. Este bloqueo es injusto, todos los hilos en espera inician operaciones setNX al mismo tiempo, y los hilos afortunados pueden conseguir el bloqueo.

Por supuesto, también hay formas de solucionarlo.

  • Hoy en día, los servicios de caché convencionales soportan el despliegue de clústeres para resolver problemas puntuales a través del clúster.
  • ¿No hay tiempo de caducidad? El método setExpire de redis soporta el tiempo de expiración entrante, y los datos se eliminan automáticamente una vez alcanzado ese tiempo.
  • ¿No bloqueante? mientras se ejecutaba repetidamente.
  • ¿No es posible volver a entrar? Después de que un hilo adquiera el bloqueo, guarda la información actual del host y del hilo, y comprueba si eres el propietario del bloqueo actual antes de obtenerlo la próxima vez.
  • ¿Injusto? Pon todos los hilos en espera en una cola antes de que un hilo adquiera un bloqueo, y luego adquiere el bloqueo en base a primero en entrar, primero en salir.


La política de sincronización del clúster Redis lleva tiempo, y es posible que el hilo A obtenga un bloqueo tras configurar NX con éxito, pero este valor no se ha actualizado al servidor donde el hilo B ejecuta setNX, lo que causará problemas de concurrencia.

Salvatore Sanfilippo, autor de redis, propuso el algoritmo Redlock, que implementa la gestión distribuida de bloqueos (DLM) más segura y fiable que un solo nodo.

El algoritmo Redlock asume que hay N nodos redis independientes entre sí, generalmente establecidos en N=5, y que estos N nodos se ejecutan en diferentes máquinas para mantener la independencia física.

Los pasos del algoritmo son los siguientes:

1. El cliente obtiene el tiempo actual en milisegundos.
2. El cliente intenta obtener el bloqueo de N nodos (cada nodo obtiene el bloqueo de la misma manera que el bloqueo de caché mencionado antes), y N nodos obtienen el bloqueo con la misma clave y valor. El cliente debe establecer el tiempo de espera de acceso a la interfaz, y el tiempo de espera de la interfaz debe ser mucho menor que el tiempo de espera del bloqueo; por ejemplo, el tiempo de liberación automática del bloqueo es de 10 segundos, y luego el tiempo de espera de la interfaz se establece en unos 5-50 ms. Esto te permite hacer un tiempo de espera lo antes posible al acceder a un nodo Redis después de que se cae, y reduce el uso normal del bloqueo.
3. El cliente calcula cuánto tiempo tarda en obtener el bloqueo, restando el tiempo obtenido en el paso 1 por el tiempo actual; solo cuando el cliente obtiene más de 3 nodos del bloqueo y el tiempo para adquirir el bloqueo es menor que el tiempo de espera del bloqueo, el cliente obtiene el bloqueo distribuido.
4. El tiempo que el cliente tiene para adquirir el bloqueo es el tiempo de espera establecido menos el tiempo de espera del bloqueo calculado en el paso 3.
5. Si el cliente no logra obtener el bloqueo, el cliente eliminará todos los bloqueos sucesivamente.
Usando el algoritmo Redlock, se puede garantizar que el servicio de bloqueo distribuido puede seguir funcionando al colgar hasta 2 nodos, lo que mejora considerablemente la disponibilidad en comparación con el bloqueo anterior de base de datos y caché.

Sin embargo, un experto distribuido escribió un artículo titulado "Cómo hacer bloqueo distribuido" cuestionando la corrección de Redlock.

El experto mencionó que hay dos aspectos a tener en cuenta al considerar cerraduras distribuidas: rendimiento y corrección.

Si usas un bloqueo distribuido de alto rendimiento y no se requiere la corrección, entonces usar un bloqueo de caché es suficiente.

Si usas una cerradura distribuida muy fiable, entonces debes considerar cuestiones estrictas de fiabilidad. Redlock, en cambio, no cumple con la corrección. ¿Por qué no? Los expertos enumeran varios aspectos.

Hoy en día, muchos lenguajes de programación usan máquinas virtuales con funciones de GC; en Full GC, el programa deja de procesar GC, a veces Full GC tarda mucho tiempo, e incluso el programa tiene unos minutos de retraso; el artículo enumera el ejemplo de HBase, HBase a veces GC durante unos minutos, lo que hará que el alquiler expire. Por ejemplo, en la figura siguiente, el cliente 1 recibe un bloqueo y está a punto de procesar un recurso compartido, y cuando está a punto de procesar un recurso compartido, se produce la GC completa hasta que el bloqueo expira. De este modo, el cliente 2 vuelve a obtener el bloqueo y empieza a trabajar en el recurso compartido. Cuando el cliente 2 está procesando, el cliente 1 completa la GC completa y comienza a procesar recursos compartidos, de modo que ambos clientes están procesando recursos compartidos.



Los expertos dieron una solución, como se muestra en la figura de abajo, parece que MVCC, lleva un token al bloqueo, token es el concepto de versión, cada vez que se completa el bloqueo de operación, el token se añade 1, lleva el token al procesar recursos compartidos, solo la versión especificada del token puede manejar el recurso compartido.



Luego el experto también dijo que el algoritmo depende de la hora local, y que Redis se basa en el método getTimeOfDay para obtener la hora en lugar del reloj monótono al manejar la expiración de la clave, lo que también conduce a inexactitudes en el tiempo. Por ejemplo, en un escenario, dos clientes 1 y cliente 2 tienen 5 nodos redis (A, B, C, D y E).

1. El Cliente 1 adquiere con éxito el bloqueo de A, B y C, y obtiene el tiempo de espera de la red de bloqueo de D y E.
2. El reloj del nodo C es inexacto, lo que provoca el tiempo de espera del bloqueo.
3. el cliente 2 adquiere con éxito el bloqueo de C, D y E, y obtiene el tiempo de espera de la red de bloqueo de A y B.
4. De este modo, tanto el cliente 1 como el cliente 2 obtienen un bloqueo.
Para resumir los dos puntos que dicen los expertos sobre la indisponibilidad de Redlock:

1. La GC y otros escenarios pueden ocurrir en cualquier momento, haciendo que el cliente obtenga un bloqueo, y el tiempo de espera de procesamiento hace que otro cliente obtenga el bloqueo. Los expertos también propusieron una solución para usar tokens auto-incrementantes.
2. El algoritmo depende de la hora local, y el reloj será inexacto, lo que resultará en que dos clientes obtengan bloqueos al mismo tiempo.
Por lo tanto, la conclusión dada por los expertos es que Redlock solo puede funcionar normalmente en el rango de retardo de red acotado, interrupción de programa acotada y error de reloj acotado, pero los límites de estos tres escenarios no pueden confirmarse, por lo que los expertos no recomiendan usar Redlock. Para escenarios con altos requisitos de corrección, los expertos recomiendan Zookeeper, que se discutirá más adelante usando Zookeeper como un candado distribuido.

Respuesta del autor de Redis

El autor de Redis respondió escribiendo un blog tras ver el artículo del experto. El autor agradeció educadamente al experto y luego expresó su desacuerdo con la opinión del experto.

Pedí un análisis en la especificación original de Redlock aquí:http://redis.io/topics/distlock.Así que gracias, Martin. Sin embargo, no estoy de acuerdo con el análisis.


La discusión del autor de REDIS sobre el uso de tokens para resolver el problema de tiempo de espera de bloqueo puede resumirse en los siguientes cinco puntos:

El punto 1, el uso de bloqueos distribuidos generalmente consiste en que no hay otra forma de controlar los recursos compartidos, los expertos usan tokens para asegurar el procesamiento de recursos compartidos, y entonces no hay necesidad de bloqueos distribuidos.
Punto 2: Para la generación de tokens, para garantizar la fiabilidad de los tokens obtenidos por diferentes clientes, el servicio que genera tokens sigue necesitando bloqueos distribuidos para garantizar la fiabilidad del servicio.
Punto 3, para la forma en que los expertos dicen que los tokens auto-incrementantes, el autor de Redis considera que es completamente innecesario, cada cliente puede generar un UUID único como token y establecer el recurso compartido a un estado que solo el cliente con el uuid pueda manejar, de modo que otros clientes no puedan procesar el recurso compartido hasta que el cliente que obtiene el bloqueo libere el bloqueo.
Como se muestra en la figura anterior, si el cliente del token 34 envía GC durante el proceso de escritura y provoca que el bloqueo expire, otro cliente puede obtener el bloqueo del token 35 y empezar a escribir de nuevo, lo que resulta en un conflicto de bloqueo. Por lo tanto, el orden de los tokens no puede combinarse con recursos compartidos.
El punto 5, el autor de Redis considera que en la mayoría de los escenarios, los bloqueos distribuidos se utilizan para gestionar problemas de actualización en escenarios no transaccionales. El autor debería referirse a que hay algunos escenarios en los que es difícil combinar tokens para gestionar recursos compartidos, así que hay que depender de los bloqueos para bloquear y procesar recursos.
Otro problema del reloj del que hablan los expertos, los autores de Redis también ofrecen una explicación. Si el tiempo que tarda en adquirir el candado es demasiado largo y supera el tiempo de espera por defecto, entonces el cliente no podrá obtener el candado en ese momento, y no habrá ejemplos propuestos por expertos.

Sentimientos personales

El primer problema que resumo es que, tras obtener un bloqueo distribuido por un cliente, este puede liberarse tras un tiempo de espera durante el procesamiento del cliente. Anteriormente, al hablar del tiempo límite establecido por el bloqueo de la base de datos de 2 minutos, si una tarea ocupa un bloqueo de orden durante más de 2 minutos, entonces el otro centro de negociación puede obtener ese bloqueo de órdenes, de modo que los dos centros puedan procesar la misma orden al mismo tiempo. En circunstancias normales, la tarea se procesa en segundos, pero a veces, el tiempo de espera establecido al unirse a una solicitud RPC es demasiado largo, y hay varias solicitudes de tiempo de espera en una tarea, es probable que el tiempo de desbloqueo automático se supere. Si escribimos en Java, puede haber GC completo en medio, así que después de desbloquear el bloqueo tras el tiempo límite, el cliente no puede percibirlo, lo cual es algo muy serio. No creo que esto sea un problema del candado en sí, mientras cualquier bloqueo distribuido mencionado anteriormente tenga las características de liberación por tiempo, este tipo de problema ocurrirá. Si usas la función de tiempo de espera del bloqueo, el cliente debe establecer el tiempo de espera del bloqueo y actuar en consecuencia, en lugar de seguir procesando el recurso compartido. El algoritmo de Redlock devuelve el tiempo de bloqueo que el cliente puede ocupar después de que el cliente adquiere el bloqueo, y el cliente debe procesar este tiempo para detener la tarea después de ese tiempo.

El segundo problema es que los expertos distribuidos no entienden Redlock. Una característica clave de Redlock es que el tiempo para adquirir el bloqueo es el tiempo total en que el bloqueo se ajusta al tiempo de espera menos el tiempo que tarda en adquirirlo, de modo que el tiempo que tarda el cliente en procesar es relativo, independientemente de la hora local.

Desde este punto de vista, la corrección de Redlock está bien garantizada. Un análisis cuidadoso de Redlock, comparado con el redis de un nodo, la característica principal que proporciona Redlock es una mayor fiabilidad, lo cual es importante en algunos escenarios. Pero creo que Redlock ha gastado demasiado dinero para lograr fiabilidad.

  • Primero, deben desplegarse 5 nodos para que Redlock sea más fiable.
  • Luego tienes que solicitar 5 nodos para conseguir el bloqueo, y mediante el método Futuro, primero puedes solicitar a 5 nodos simultáneamente y luego obtener el resultado de respuesta, lo que puede acortar el tiempo de respuesta, pero aún así lleva más tiempo que un bloqueo Redis de un solo nodo.
  • Luego, como es necesario obtener más de 3 de los 5 nodos, puede haber un conflicto de bloqueo, es decir, todos han obtenido 1-2 bloqueos y, como resultado, nadie puede conseguirlo; este problema, el autor de Redis toma prestada la esencia del algoritmo de balsa, a través de la colisión en tiempo aleatorio, el tiempo de conflicto puede reducirse considerablemente, pero este problema no puede evitarse muy bien, especialmente cuando el bloqueo se adquiere por primera vez, por lo que el coste de tiempo para adquirirlo aumenta.
  • Si 2 de los 5 nodos están caídos, la disponibilidad del bloqueo se reducirá considerablemente; primero, debes esperar a que los resultados de estos dos nodos caídos expiren antes de volver, y solo quedan 3 nodos, y el cliente debe obtener los bloqueos de los 3 nodos para tener el bloqueo, lo cual también es más difícil.
  • Si existe una partición de red, puede darse una situación en la que el cliente nunca pueda obtener el bloqueo.


Después de analizar tantas razones, creo que el punto más crítico del problema de Redlock es que Redlock requiere que los clientes aseguren la consistencia de las escrituras, y los 5 nodos del backend son completamente independientes, y todos los clientes tienen que operar esos 5 nodos. Si hay un líder entre 5 nodos, el cliente puede sincronizar los datos del líder siempre que el cliente obtenga el bloqueo del líder, de modo que no habrá problemas como particionamientos, tiempos de espera ni conflictos. Por lo tanto, para garantizar la corrección de los bloqueos distribuidos, creo que usar un servicio de coordinación distribuido con una fuerte consistencia puede resolver mejor el problema.

Vuelve a surgir la pregunta: ¿cuánto tiempo debería establecer el tiempo de caducidad? Cómo establecer el tiempo de invalidación es demasiado corto, y el bloqueo se libera automáticamente antes de ejecutar el método, por lo que habrá problemas de concurrencia. Si tarda demasiado, otros hilos que se bloquean pueden tener que esperar mucho.

Este problema también existe con el uso de bases de datos para implementar bloqueos distribuidos.

El enfoque actual y corriente para este problema es establecer un tiempo de espera corto para cada bloqueo obtenido y iniciar un hilo para actualizar el tiempo de espera cada vez que esté a punto de alcanzarlo. Termina este hilo al mismo tiempo que se libera la cerradura. Por ejemplo, redisson, el componente oficial de bloqueo distribuido de redis, utiliza esta solución.

Ventajas de usar caché para implementar bloqueos distribuidos
Buen rendimiento.

Desventajas de usar caché para implementar bloqueos distribuidos
La implementación es demasiado responsable, hay demasiados factores a tener en cuenta.

Bloqueos distribuidos basados en la implementación de Zookeeper

Bloqueos distribuidos basados en nodos temporales ordenados de Zookeeper.

La idea general es que cuando cada cliente bloquea un método, se genera un nodo ordenado instantáneo único en el directorio del nodo especificado correspondiente al método en zookeeper. La forma de determinar si se consigue un bloqueo es sencilla, solo tienes que determinar el que tiene el número de serie más pequeño en el nodo ordenado. Cuando se libera el bloqueo, simplemente elimina el nodo instantáneo. Al mismo tiempo, puede evitar el problema de bloqueos causados por el tiempo de inactividad del servicio que no se puede liberar.

Veamos si Zookeeper puede resolver los problemas mencionados antes.

  • ¿La cerradura no se libera? Usar Zookeeper puede resolver eficazmente el problema de que los bloqueos no se liberen, porque al crear un bloqueo, el cliente creará un nodo temporal en ZK, y una vez que el cliente obtiene el bloqueo y lo cuelga de repente (la conexión de la sesión está rota), el nodo temporal se elimina automáticamente. Otros clientes pueden volver a conseguir la cerradura.
  • ¿Cerraduras que no bloquean? Una vez que el nodo cambia, Zookeeper notificará al cliente, y este podrá comprobar si el nodo creado es el número ordinal más pequeño entre todos los nodos.
  • ¿No puedes volver a entrar? Cuando el cliente crea un nodo, escribe directamente la información del host y la información del hilo del cliente actual en el nodo, y la próxima vez que quieras obtener el bloqueo, puedes compararlo con los datos del nodo más pequeño actual. Si la información es la misma que la tuya, entonces puedes obtener directamente el bloqueo y, si es diferente, crear un nodo secuencial temporal para participar en la cola.


La pregunta vuelve a surgir: sabemos que Zookeeper necesita desplegarse en clústeres, ¿habrá problemas de sincronización de datos como en los clústeres de Redis?

Zookeeper es un componente distribuido que garantiza una consistencia débil, es decir, la consistencia eventual.

Zookeeper emplea un protocolo de sincronización de datos llamado Protocolo Basado en Quórum. Si hay N servidores Zookeeper en el clúster Zookeeper (N suele ser impar, 3 pueden cumplir con fiabilidad de datos y alto rendimiento de lectura y escritura, y 5 tienen el mejor equilibrio entre fiabilidad de datos y rendimiento de lectura y escritura), entonces una operación de escritura del usuario se sincroniza primero con N/2 + 1 servidores y luego se devuelve al usuario, solicitando que escriba correctamente. El protocolo de sincronización de datos basado en el Protocolo Basado en Quórum determina la consistencia de la potencia que Zookeeper puede soportar.

En un entorno distribuido, el almacenamiento de datos que cumple con una fuerte consistencia es prácticamente inexistente, y requiere que todos los nodos se actualicen de forma sincrónica al actualizar los datos de un nodo. Esta estrategia de sincronización aparece en la base de datos de replicación síncrona maestro-esclavo. Sin embargo, esta estrategia de sincronización tiene demasiado impacto en el rendimiento de escritura y rara vez se observa en la práctica. Como Zookeeper escribe N/2+1 nodos de forma síncrona, y N/2 nodos no se actualizan de forma síncrona, Zookeeper no es muy consistente.

La operación de actualización de datos del usuario no garantiza que las lecturas posteriores lean el valor actualizado, sino que eventualmente mostrará consistencia. Sacrificar la consistencia no significa ignorar completamente la consistencia de los datos; de lo contrario, los datos son caóticos, así que no importa lo alta que sea la disponibilidad del sistema, ni lo buena que sea la distribución, no tiene valor. Sacrificar la consistencia es simplemente que ya no se requiere una consistencia fuerte en bases de datos relacionales, pero siempre que el sistema pueda lograr una consistencia eventual.

¿Una pregunta de un solo punto? Usar Zookeeper puede resolver eficazmente un problema puntual, ZK se despliega en clústeres, y mientras más de la mitad de las máquinas del clúster sobrevivan, el servicio puede proporcionarse al mundo exterior.

¿Problemas de equidad? Usar Zookeeper puede resolver el problema de los bloqueos justos, los nodos temporales creados por el cliente en ZK están ordenados, y cada vez que se libera el bloqueo, ZK puede notificar al nodo más pequeño que obtenga el bloqueo, asegurando la equidad.

La pregunta vuelve a surgir: sabemos que Zookeeper necesita desplegarse en clústeres, ¿habrá problemas de sincronización de datos como en los clústeres de Redis?

Zookeeper es un componente distribuido que garantiza una consistencia débil, es decir, la consistencia eventual.

Zookeeper emplea un protocolo de sincronización de datos llamado Protocolo Basado en Quórum. Si hay N servidores Zookeeper en el clúster Zookeeper (N suele ser impar, 3 pueden cumplir con fiabilidad de datos y alto rendimiento de lectura y escritura, y 5 tienen el mejor equilibrio entre fiabilidad de datos y rendimiento de lectura y escritura), entonces una operación de escritura del usuario se sincroniza primero con N/2 + 1 servidores y luego se devuelve al usuario, solicitando que escriba correctamente. El protocolo de sincronización de datos basado en el Protocolo Basado en Quórum determina la consistencia de la potencia que Zookeeper puede soportar.

En un entorno distribuido, el almacenamiento de datos que cumple con una fuerte consistencia es prácticamente inexistente, y requiere que todos los nodos se actualicen de forma sincrónica al actualizar los datos de un nodo. Esta estrategia de sincronización aparece en la base de datos de replicación síncrona maestro-esclavo. Sin embargo, esta estrategia de sincronización tiene demasiado impacto en el rendimiento de escritura y rara vez se observa en la práctica. Como Zookeeper escribe N/2+1 nodos de forma síncrona, y N/2 nodos no se actualizan de forma síncrona, Zookeeper no es muy consistente.

La operación de actualización de datos del usuario no garantiza que las lecturas posteriores lean el valor actualizado, sino que eventualmente mostrará consistencia. Sacrificar la consistencia no significa ignorar completamente la consistencia de los datos; de lo contrario, los datos son caóticos, así que no importa lo alta que sea la disponibilidad del sistema, ni lo buena que sea la distribución, no tiene valor. Sacrificar la consistencia es simplemente que ya no se requiere una consistencia fuerte en bases de datos relacionales, pero siempre que el sistema pueda lograr una consistencia eventual.

Si Zookeeper cumple la consistencia causal depende de cómo se programa el cliente.

Prácticas que no satisfacen la consistencia causal

  • El proceso A escribe un dato en el /z de Zookeeper y lo devuelve con éxito
  • El proceso A informa al proceso B de que A ha modificado los datos de /z
  • B lee los datos de la /z de Zookeeper
  • Dado que el servidor del Cuidador conectado a B puede que no haya sido actualizado con los datos escritos de A, entonces B no podrá leer los datos escritos de A


Prácticas que cumplen con la consistencia causal

  • El Proceso B escucha cambios de datos en /z en Zookeeper
  • El proceso A escribe un dato en el /z de Zookeeper y, antes de que devuelva con éxito, Zookeeper debe llamar al oyente registrado en /z, y el líder notificará a B el cambio de datos
  • Después de que se responde al método de respuesta a eventos del proceso B, toma los datos cambiados, por lo que B definitivamente podrá obtener el valor modificado
  • La consistencia causal aquí se refiere a la consistencia causal entre el líder y B, es decir, el líder notifica los datos de un cambio


El segundo mecanismo de escucha de eventos es también el método que debe usarse para programar correctamente Zookeeper, por lo que Zookeeper debe cumplir con la consistencia causal

Por lo tanto, cuando implementamos bloqueos distribuidos basados en Zookeeper, deberíamos usar la práctica de satisfacer la consistencia causal, es decir, los hilos que esperan el bloqueo escuchan los cambios en el bloqueo de Zookeeper, y cuando el bloqueo se libera, Zookeeper notificará al hilo en espera que cumpla las condiciones de bloqueo justo.

Puedes usar directamente el cliente de biblioteca de terceros Zookeeper, que encapsula un servicio de bloqueo de reentrada.

Los bloqueos distribuidos implementados con ZK parecen encajar exactamente con lo que esperábamos de un bloqueo distribuido al principio de este artículo. Sin embargo, no lo es, y el bloqueo distribuido implementado por Zookeeper tiene en realidad una desventaja: el rendimiento puede no ser tan alto como el del servicio de caché. Porque cada vez que se crea y libera un bloqueo, se deben crear y destruir dinámicamente nodos instantáneos para realizar la función de bloqueo. La creación y eliminación de nodos en ZK solo puede realizarse a través del servidor líder, y luego los datos se comparten con todas las máquinas seguidoras.

Ventajas de usar Zookeeper para implementar cerraduras distribuidas
Resolver eficazmente problemas de punto único, problemas de no reentrada, problemas de no bloqueo y fallos de desbloqueo del bloqueo. Es relativamente sencillo de implementar.

Desventajas de usar Zookeeper para implementar cerraduras distribuidas
El rendimiento no es tan bueno como usar caché para implementar bloqueos distribuidos. Se requiere comprensión de los principios de ZK.

Comparación de las tres opciones

Desde la perspectiva de la facilidad de comprensión (de lo bajo a lo alto)
Base de datos > caché > Zookeeper

Desde la perspectiva de la complejidad de la implementación (de baja a alta)
Bases de datos > caché de Zookeeper >

Desde la perspectiva del rendimiento (de alto a bajo)
Almacenamiento en caché > Zookeeper >= base de datos

Desde una perspectiva de fiabilidad (de alta a baja)
Bases de datos > caché de Zookeeper >





Anterior:Diferencia entre anotaciones @Bean primavera y @Service
Próximo:Tutorial en vídeo para aprender el lenguaje C desde cero
 Propietario| Publicado en 22/9/2020 17:34:33 |
[Combate real]. NET Core implementa bloqueos distribuidos basados en Redis
https://www.itsvse.com/thread-9391-1-1.html

Implementación de bloqueo distribuido de .net/c# Zookeeper [Código fuente]
https://www.itsvse.com/thread-4651-1-1.html

Renuncia:
Todo el software, materiales de programación o artículos publicados por Code Farmer Network son únicamente para fines de aprendizaje e investigación; El contenido anterior no se utilizará con fines comerciales o ilegales; de lo contrario, los usuarios asumirán todas las consecuencias. La información de este sitio proviene de Internet, y las disputas de derechos de autor no tienen nada que ver con este sitio. Debes eliminar completamente el contenido anterior de tu ordenador en un plazo de 24 horas desde la descarga. Si te gusta el programa, por favor apoya el software genuino, compra el registro y obtén mejores servicios genuinos. Si hay alguna infracción, por favor contáctanos por correo electrónico.

Mail To:help@itsvse.com