Distribuído Bloquear as três maneiras - o absoluto clássico

1, com base no banco de dados:

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

2, com base na cache de: utilizando SETNX () retorna o valor
3, com base no ZooKeeper:

 a、利用Zookeeper同一个目录下只能有一个唯一文件名
 b、利用Zookeeper分布式锁客户端Curator
Nota: Os fatores a considerar: um único ponto, reentrada, obstrução, tempo de falha

Em primeiro lugar, com base na implementação do banco de dados

A idéia central é baseado na forma como o banco de dados: Criar uma tabela no banco de dados, a tabela contém o nome do método e outros campos, e criar um índice exclusivo no campo nome do método, você quer executar um método, usar este nome de método para a mesa inserção de dados, instruções inseridas com sucesso pode adquirir o bloqueio, excluir a linha correspondente após a conclusão dos dados liberar o bloqueio.
1. Criar uma tabela

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 executar um método, use este método para inserir dados em um nome de tabela:

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

Porque o nosso method_name fez uma restrição exclusiva, onde se houver vários pedidos simultaneamente submetidos ao banco de dados, o banco de dados irá garantir que apenas uma operação pode ser bem sucedido, então podemos assumir que rosca o sucesso da operação para adquirir o bloqueio do método pode ser realizada método de conteúdo.
3, o bloqueio é adquirido com sucesso inserido, após a conclusão da eliminação da linha de dados correspondente liberta o bloqueio;

delete from method_lock where method_name ='methodName';

Nota: Esta é apenas uma maneira de usar baseada em banco de dados, implementação de banco de dados distribuído usando fechaduras e muitos outros jogos são jogados;
implementações de banco de dados uso com base nesta muito simples, mas as condições para que deveria ter distribuído bloqueio, também outras questões precisam ser abordadas e optimização:

  • Porque é implementada numa base de dados, a base de dados sobre a disponibilidade e o desempenho vai afectar directamente o desempenho e disponibilidade de bloqueio distribuído, por conseguinte, os dados de implantação dual do sistema, dados de sincronização, de comutação de espera;
  • Não têm a característica de reentrada, porque o mesmo fio até que o bloqueio é liberado, tem havido uma linha de dados, os dados não podem ser inseridos com sucesso mais uma vez, por isso a necessidade de adicionar em uma mesa para registro de informações na máquina atual e linha para adquirir o bloqueio, em adquirir o bloqueio novamente quando a primeira máquina e linha informações da tabela look-up e se a máquina atual e passe o mesmo, se o mesmo é o acesso directo à fechadura;
  • Não há mecanismos de falha de bloqueio, que não são susceptíveis de ocorrer dados depois inseridos com sucesso, o servidor está em baixo, os dados correspondentes não é excluído quando o serviço estiver disponível, não obter um bloqueio, por isso a necessidade de adicionar em um para gravação tempo de expiração, ea necessidade de trabalho regular limpa o inválido dados;
  • Não tem as características de bloqueio de bloqueios, bloqueio não obter retornos diretos um fracasso, é necessário otimizar a lógica de aquisição, muitas vezes para obter a circulação;
  • Vai encontrar uma variedade de problemas no processo de implementação, a fim de resolver estes problemas, a implementação será mais complexo, dependendo do banco de dados requer algum recurso sobrecarga, problemas de desempenho a considerar.

Em segundo lugar, com base na implementação Redis

1, a escolha de implementar bloqueio distribuído Redis razões:

um, Redis tem um alto desempenho
b, comandos Redis apoiar esta melhor, conseguir mais conveniente

2, use a descrição do comando:

um, SETNX: SETNX chave val: se e somente se não houver, chave SET é uma seqüência de val, retorna 1; quando a chave estiver presente, então nada e retorna 0;
B, A expirar: O expirar tempo limite fundamental: é chave para definir um tempo limite de tempo, no segundo, ao longo deste tempo o bloqueio é automaticamente liberado para impasse evitar.
c, delete: tecla delete: tecla Delete

3, para realizar ideias:

  • Ao adquirir o bloqueio, com setnx bloqueio, e use o comando para adicionar um tempo limite expirar o tempo do bloqueio, a mudança ao longo do tempo é automaticamente liberar o bloqueio, o valor de bloqueio é uma UUID gerado aleatoriamente. Quando a determinação pelo bloqueio libertar este.
  • Adquirir um bloqueio quando se definir um tempo limite adquirida ao longo deste tempo se você desistir de adquirir o bloqueio.
  • Quando o bloqueio é liberado pelo julgamento UUID não é o bloqueio, se o bloqueio, você bloquear a exclusão foram liberados.
 /**
 * @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;
    }
}

Em terceiro lugar, com base na implementação de Zookeeper

Zookeeper é fornecer um serviço consistente para aplicações distribuídas componentes de código aberto dentro dele é uma estrutura hierárquica árvore de diretórios do sistema de arquivos, as disposições do mesmo diretório só pode ter um nome de arquivo exclusivo. Tratador passo baseia-se na implementação de bloqueio distribuído:

  1. A myLock diretório membro de desgaste
  2. Um fio adquire o bloqueio apenas quer criar uma ordem temporária de nós no diretório myLock;
  3. Obtém todos os nós filho sob o diretório myLock, e, em seguida, ficar menor do que seus irmãos, e se não, então o segmento atual é o número de seqüência menor, obter um bloqueio;
  4. Tópico B adquirir todos os nós, determinar se ele é o menor nó, os tempos de escuta conjunto menor do que o seu próprio nó;
  5. A transformação da linha é completa, remova o próprio nó, linha B ouvir os eventos de alteração, determinar que ele não é o menor nó, se ele é, então, obter o bloqueio.

Nota: Recomenda-se com a biblioteca Apache open source curador, é um cliente Zookeeper, curador fornecido InterProcessMutex é conseguir um bloqueio distribuído, adquirir o método utilizado para obter o bloqueio, o método de liberação para liberar o bloqueio;

Vantagens: com elevada disponibilidade, reentrante, característica fechaduras de bloqueio pode ser uma boa solução para as falhas de bloqueio.
Contras: por causa da necessidade frequente de criar e nós de exclusão, como o desempenho rápido Redis maneira;

Publicado 21 artigos originais · ganhou elogios 4 · Visualizações 514

Acho que você gosta

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