¿Cómo utilizar Redis para implementar la función de bloqueo distribuido?
Dado que Redis tiene un solo subproceso y tiene un rendimiento rápido, es más adecuado para bloqueos distribuidos globales.
El proceso básico es utilizar una clave global única para determinar si otros subprocesos están ocupando el recurso cuando se opera un recurso global en conflicto. Si otros subprocesos están ocupando el recurso, se informará un error y el recurso. se saldrá o el sistema esperará en un bucle. Si ningún otro subproceso lo ocupa, puede agregar un bloqueo distribuido para ocupar este recurso y luego realizar tareas posteriores. Una vez completada la ejecución de la tarea, se libera el bloqueo distribuido y otros subprocesos pueden continuar usando este recurso.
Entonces, ¿cuál es la acción de bloquear a través de Redis?
Comando de bloqueo simple:
El comando es: setnx
El mecanismo de implementación interno es determinar si hay datos en la posición de la clave. datos, configúrelo en value Return, si hay datos, se devuelve un valor especial.
Pero hay un problema aquí. Si el hilo que ocupa el recurso sale por error y no tiene tiempo para liberar el bloqueo distribuido, el bloqueo quedará ocupado para siempre.
Versión mejorada de. bloqueo:
Los comandos son: 1. setnx 2. expire
Al agregar un bloqueo distribuido, agregue un tiempo de vencimiento del bloqueo. De esta manera, cuando el hilo de bloqueo salga, el bloqueo tendrá la posibilidad de liberarse después de al menos un período de tiempo.
Un pequeño problema aquí es que estos dos comandos se ejecutan por separado y no son operaciones atómicas. Luego existe la posibilidad teórica de que después de ejecutar el primer comando, se produzca un error y sea demasiado tarde para ejecutar el comando de caducidad. Una forma es escribir un script Lua usted mismo, que puede lograr la ejecución atómica de múltiples comandos. Una forma es hacer referencia a algunas bibliotecas de código abierto. Después de la versión 2.8, para resolver este problema, redis proporcionó una solución oficial, que es el comando: set key value nx expireTimeNum ex, que combina los dos comandos anteriores en un solo comando.
Con el tiempo de vencimiento se soluciona parte del problema, pero también es posible que los bloqueos hayan expirado, pero las tareas ejecutadas en el medio aún no hayan finalizado. El primer hilo aún se está ejecutando y. el segundo subproceso ya ha tomado el Cuando el bloqueo comienza a ejecutarse, si el primer subproceso completa la ejecución, el bloqueo del segundo subproceso se liberará. Cuando el segundo subproceso libera el bloqueo, se produce un error o se libera el bloqueo de otro subproceso, lo que no cumple con las expectativas.
Si simplemente desea resolver este problema, puede usar un número aleatorio al establecer el valor. Al liberar el bloqueo, primero determine si el número aleatorio es consistente y elimine el bloqueo. de lo contrario, salga. Pero juzgar el valor y eliminar la clave no es una operación atómica. En este momento, es necesario utilizar el script Lua.
La solución anterior aún no puede resolver el problema de la liberación del tiempo de espera y aún viola la intención original de los bloqueos distribuidos. ¿Qué pasó?
La idea de resolver el problema es iniciar otro hilo. Su tarea es juzgar de vez en cuando si se descubre que la tarea del hilo actual está a punto de caducar y aún no lo ha hecho. se ha completado, entonces el bloqueo del hilo actual se renovará periódicamente.
Existe una biblioteca de código abierto que resuelve este problema y lo más probable es que sea mejor que tú. Esta biblioteca es Redisson, que es muy fácil de recordar. Es hijo de Redis, y juntos son Reidsson. Aunque puede que no estén relacionados, es suficiente.
Hay un componente en esta biblioteca llamado perro guardián, que literalmente se traduce como perro guardián. Su función es juzgar a intervalos.
Si seguimos pensando en ello, hay un problema más extremo: si redis es un nodo único, está inactivo o es un nodo primario y de respaldo, pero el nodo de respaldo no ha tenido tiempo; Para sincronizar los datos del nodo principal, después de que el nodo maestro obtiene el bloqueo, se desactiva inmediatamente antes de sincronizar los datos y también puede ocurrir el problema de no poder bloquear. Si crees que esto es un problema y quieres solucionarlo, ¿cómo lo solucionas?
La idea es bloquear algunos servidores redis más al bloquear. Por lo general, cuando se implementa redis, es 2n + 1, por lo que al bloquear, debe asegurarse de que más de la mitad de los servidores funcionen correctamente. bloqueado. Es decir n+1 servidores.
A menos que todo el clúster no esté disponible en este momento, la seguridad mejorará enormemente.
Este problema también se resuelve con una biblioteca de código abierto, que es Redis Red Lock.
La siguiente pregunta es: ¿pueden los bloqueos distribuidos ser reentrantes?
Si desea implementar un bloqueo distribuido reentrante, debe agregar información del hilo y del número de bloqueo al establecer el valor. Pero esta es una idea simple, si se agregan cuestiones como el tiempo de vencimiento, los bloqueos reentrantes pueden volverse más complicados.