Bloqueo distribuido las tres formas - el clásico absoluto

1, basado en la base de datos:

 a、利用唯一索引约束;
 b、利用数据自带的排他锁

2, basado en el cache: usando SETNX () devuelve el valor
3, basado en el ZooKeeper:

 a、利用Zookeeper同一个目录下只能有一个唯一文件名
 b、利用Zookeeper分布式锁客户端Curator
Nota: Los factores a considerar: un único punto, por reentrada, obstrucción, tiempo de fallo

En primer lugar, en base a la implementación de la base de datos

La idea central se basa en la forma en la base de datos: Crear una tabla en la base de datos, la tabla contiene el nombre del método y otros campos, y crear un índice único en el campo nombre del método, que desea ejecutar un método, utilizar este nombre de método a la mesa insertar datos, instrucciones insertadas con éxito pueden adquirir el bloqueo, eliminar la fila correspondiente después de la finalización de los datos de liberar el bloqueo.
1. Crear una tabla

DROP TABLE IF EXISTS `method_lock`;
CREATE TABLE `method_lock` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `method_name` varchar(64) NOT NULL COMMENT '锁定的方法名',
  `desc1` varchar(255) NOT NULL COMMENT '备注信息',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uidx_method_name` (`method_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='锁定中的方法';

2, queremos ejecutar un método, utilice este método para insertar datos en un nombre de tabla:

INSERT INTO method_lock (method_name, desc1) VALUES ('methodName', '测试的methodName');

Debido a que nuestro method_name hizo una restricción única, en la que si hay múltiples solicitudes presentadas simultáneamente a la base de datos, la base de datos se asegurará de que sólo una operación puede tener éxito, entonces podemos suponer que el hilo del éxito de la operación para adquirir el bloqueo del método se puede realizar método de contenido.
3, la cerradura se adquiere insertado con éxito, después de la finalización de la supresión de la línea correspondiente de los datos libera el bloqueo;

delete from method_lock where method_name ='methodName';

Nota: Esto es sólo una manera de usar basado en la base de datos, aplicación de base de datos distribuida con cerraduras y muchos otros juegos se juegan;
implementaciones de bases de datos basados en el uso de este muy simple, pero las condiciones para ello deberían haber distribuido bloqueo, sino que también otros asuntos deben ser abordados y optimización:

  • Debido a que se implementa en una base de datos, la base de datos de la disponibilidad y el rendimiento afectará directamente al rendimiento y la disponibilidad de bloqueo distribuido, por lo tanto, los datos de despliegue de doble sistema, la sincronización de datos, conmutación de modo de espera;
  • No tienen la característica de reentrada debido a que el mismo hilo hasta que el bloqueo se libera, se ha producido una línea de datos, los datos no se puede insertar con éxito de nuevo, por lo que la necesidad de poner en una tabla para registrar la información de la máquina y el hilo actual para adquirir el bloqueo, en la adquisición de la cerradura de nuevo cuando la primera mesa de la máquina y el hilo de la información de consulta y si el equipo actual y el hilo de la misma, si el mismo es un acceso directo a la cerradura;
  • No hay mecanismos de fallo de bloqueo, que es probable que ocurra después de los datos introducidos con éxito, el servidor no funciona, los datos correspondientes no se borran cuando el servicio esté disponible, no ha obtener un bloqueo, por lo que la necesidad de poner en uno para la grabación fecha de caducidad, y la necesidad de trabajo regular purga la inválido datos;
  • No tiene las características de bloqueo de cerraduras, cerradura no obtener retornos directos un fracaso, es necesario optimizar la lógica de adquisición, muchas veces para obtener la circulación;
  • Se encontrará con una variedad de problemas en el proceso de aplicación, con el fin de resolver estos problemas, la aplicación será más complejo, dependiendo de la base de datos requiere algún recurso cabeza, problemas de rendimiento a tener en cuenta.

En segundo lugar, basándose en la ejecución Redis

1, la elección de la aplicación de bloqueo distribuido ReDiS razones:

una, Redis tiene un alto rendimiento
b, comandos Redis apoyar esto mejor, lograr más conveniente

2, utilice la descripción del comando:

una, SETNX: SETNX clave val: si y sólo si no hay, tecla SET es una cadena de Val, devuelve 1; cuando la llave está presente, entonces nada y devuelve 0;
B, La expiran: El expira el tiempo de espera clave: es clave para establecer una hora de tiempo de espera, en segundos, durante este tiempo el bloqueo se libera automáticamente a punto muerto evitan.
c, suprimir: tecla de borrar: tecla Supr

3, para darse cuenta de las ideas:

  • Al adquirir la cerradura, la cerradura setnx, y utilizar el comando para agregar un tiempo de espera expire el tiempo de la cerradura, cambian con el tiempo se liberar automáticamente el bloqueo, el valor de bloqueo es un UUID generado aleatoriamente. Cuando la determinación por el bloqueo de seguridad de este.
  • Adquirir un bloqueo cuando se establece un tiempo de espera adquirido durante este tiempo si usted renuncia a adquirir el bloqueo.
  • Cuando el bloqueo se libera por el juicio UUID no es el bloqueo, si el bloqueo, se bloquea la eliminación fueron puestos en libertad.
 /**
 * @author zhengzheng046
 */
public class DistributedLok {

    private final JedisPool jedisPool;

    public DistributedLok(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }

    /**
     * 获取锁
     *
     * @param lockname
     * @param acquireTimeOut
     * @param timeout
     * @return
     */

    public String lockWithTimeout(String lockname, long acquireTimeOut, long timeout) {

        Jedis conn = null;
        String retIdentifier = null;

        try {
            conn = jedisPool.getResource();
            String identifier = UUID.randomUUID().toString();
            //锁名,即key值
            String lockKey = "lock:" + lockname;
            //超时时间,上锁后超过时间,自动释放
            int lockExpire = (int) timeout / 1000;

            //获取锁的超时时间,超过这个时间,锁自动释放
            long end = System.currentTimeMillis() + acquireTimeOut;

            while (System.currentTimeMillis() < end) {
                if (conn.setnx(lockKey, identifier) == 1) {
                    conn.expire(lockKey, lockExpire);
                    retIdentifier = identifier;
                    return retIdentifier;
                }

                if (conn.tt1(lockKey) == -1) {
                    conn.expire(lockKey, lockExpire);
                }

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //连接关闭
            conn.close();
        }
        return retIdentifier;
    }

    /**
     * 释放锁
     * @param lockName
     * @param identifier
     * @return
     */
    public boolean releaseLock(String lockName, String identifier) {
        Jedis conn = null;
        String lockKey = "lock:" + lockName;
        boolean retflag = false;
        try {
            conn = jedisPool.getResource();
            while(true){
                //监视lock,准备开启事务
                conn.watch(lockKey);
                //通过前面返回的value值判断是不是该锁,若是改锁,则删除,释放锁

                if (identifier.equals(conn.get(lockKey))){
                    Transaction transaction =  conn.multi();
                    transaction.del(lockKey);
                    List<Object> results = transaction.exec();
                    if (results == null){
                        continue;
                    }
                    retflag = true;
                  conn.unwatch();
                  break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conn.close();
        }
        return retflag;
    }
}

En tercer lugar, basada en la aplicación del Zookeeper

Zookeeper es proporcionar un servicio consistente para aplicaciones distribuidas componentes de código abierto en su interior es una estructura de árbol de directorios del sistema de archivos jerárquico, lo dispuesto en el mismo directorio sólo puede tener un nombre de archivo único. Zookeeper paso se basa en la aplicación de bloqueo distribuido:

  1. Un directorio myLock elemento de desgaste
  2. Un hilo adquiere el bloqueo sólo quieren crear una orden temporal de los nodos en el directorio myLock;
  3. Obtiene todos los nodos secundarios en el directorio myLock, y luego se hacen más pequeños que sus hermanos, y si no, entonces el hilo actual es el número de secuencia más pequeño, obtener un bloqueo;
  4. Hilo B adquirir la totalidad de los nodos, determinar si es el nodo más pequeño, conjunto tiempos de escucha más pequeño que su propio nodo;
  5. Un hilo de procesamiento, retire el propio nodo, el subproceso B escucha a los eventos de cambio, determinar que no es el nodo más pequeño, si está a continuación, obtener la cerradura.

Nota: Se recomienda la biblioteca de código abierto Apache Conservador, es un cliente Zookeeper, curador proporciona InterProcessMutex es lograr un bloqueo distribuido, adquirir el método utilizado para obtener el bloqueo, el método de liberación para liberar la cerradura;

Ventajas: alta disponibilidad, por reentrada, el bloqueo de las cerraduras característica puede ser una buena solución a los fallos de seguridad.
Contras: Debido a la frecuente necesidad de crear y nodos de eliminación, como un rendimiento rápido ReDiS manera;

Publicado 21 artículos originales · ganado elogios 4 · Vistas 514

Supongo que te gusta

Origin blog.csdn.net/weixin_39617728/article/details/104828021
Recomendado
Clasificación