Evolução de bloqueio distribuído RedisTemplate, implementação de bloqueio distribuído de redistribuição!

A evolução dos bloqueios distribuídos

Fundamental

Podemos ir a um local para “ocupar um fosso” ao mesmo tempo, e se o ocuparmos, executar a lógica. Caso contrário, você deverá esperar até que o bloqueio seja liberado. "Zhankeng" pode ir para o redis, para o banco de dados e para qualquer lugar que todos possam acessar. Esperando uma maneira de girar.

Estágio um


 

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        //阶段一
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111");
        //获取到锁,执行业务
        if (lock) {
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            //删除锁,如果在此之前报错或宕机会造成死锁
            stringRedisTemplate.delete("lock");
            return categoriesDb;
        }else {
            //没获取到锁,等待100ms重试
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }
    }
 
public Map<String, List<Catalog2Vo>> getCategoryMap() {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        String catalogJson = ops.get("catalogJson");
        if (StringUtils.isEmpty(catalogJson)) {
            System.out.println("缓存不命中,准备查询数据库。。。");
            Map<String, List<Catalog2Vo>> categoriesDb= getCategoriesDb();
            String toJSONString = JSON.toJSONString(categoriesDb);
            ops.set("catalogJson", toJSONString);
            return categoriesDb;
        }
        System.out.println("缓存命中。。。。");
        Map<String, List<Catalog2Vo>> listMap = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Catalog2Vo>>>() {});
        return listMap;
    }

Perguntas: 1. setnx ocupa uma posição, o código comercial está anormal ou o programa trava durante o processo da página. A lógica de bloqueio de exclusão não é executada, o que causa um conflito

Solução: Defina a expiração automática do bloqueio, mesmo que não seja excluído, ele será excluído automaticamente

Estágio 2


 

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111");
        if (lock) {
            //设置过期时间
            stringRedisTemplate.expire("lock", 30, TimeUnit.SECONDS);
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            stringRedisTemplate.delete("lock");
            return categoriesDb;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }​​​​​​​

Pergunta: 1. O setnx está configurado e estou prestes a definir o tempo de expiração e o sistema trava. Impasse novamente. Solução: A configuração do tempo de expiração e do espaço reservado deve ser atômica. redis suporta o uso do comando setnx ex

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
    //加锁的同时设置过期时间,二者是原子性操作
    Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "1111",5, TimeUnit.SECONDS);
    if (lock) {
        Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
        //模拟超长的业务执行时间
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stringRedisTemplate.delete("lock");
        return categoriesDb;
    }else {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getCatalogJsonDbWithRedisLock();
    }
}

Pergunta: 1. Excluir o bloqueio diretamente? ? ? Se o próprio bloqueio expirar devido a um longo período comercial, nós o excluímos diretamente e é possível excluir o bloqueio que outras pessoas estão mantendo. Solução: Ao ocupar o bloqueio, o valor é especificado como uuid, e cada pessoa corresponde ao seu próprio bloqueio antes de excluí-lo.

Estágio quatro

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        String uuid = UUID.randomUUID().toString();
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
         //为当前锁设置唯一的uuid,只有当uuid相同时才会进行删除锁的操作
        Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
        if (lock) {
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            String lockValue = ops.get("lock");
            if (lockValue.equals(uuid)) {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                stringRedisTemplate.delete("lock");
            }
            return categoriesDb;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }
    }


Pergunta: 1. Se for considerado o valor atual, quando o bloqueio estiver prestes a ser excluído, o bloqueio expirou e outra pessoa o definiu com um novo valor. Então o que excluímos é a solução de bloqueio de outra pessoa: a exclusão de bloqueios deve garantir a atomicidade. Concluído usando o script redis+Lua

Estágio Cinco – Forma Final

 public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        String uuid = UUID.randomUUID().toString();
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
        if (lock) {
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            String lockValue = ops.get("lock");
            String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                    "    return redis.call(\"del\",KEYS[1])\n" +
                    "else\n" +
                    "    return 0\n" +
                    "end";
            stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), lockValue);
            return categoriesDb;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }
    }

4) Redisson
Redisson é uma grade de dados na memória Java (In-Memory Data Grid) implementada com base no Redis. Ele não apenas fornece uma série de objetos Java comuns distribuídos, mas também fornece muitos serviços distribuídos. Estes incluem (BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service , Serviço de agendador) Redisson fornece a maneira mais fácil e conveniente de usar o Redis. O objetivo do Redisson é promover a separação de preocupações dos usuários (Separação de Preocupações) do Redis, para que os usuários possam se concentrar mais no processamento da lógica de negócios.

 

 

Acho que você gosta

Origin blog.csdn.net/guoweiting/article/details/115379589
Recomendado
Clasificación