Bloqueos distribuidos + problemas de almacenamiento en caché distribuido utilizan redis (redisson) para implementar bloqueos distribuidos

Bloqueo distribuido + problema de caché distribuida

  • En el modo de microservicio, varios servicios idénticos deben mantener la coherencia de los datos de la base de datos. En este momento, debe evolucionar de un bloqueo local a un bloqueo distribuido.
  • Esta publicación de blog plantea continuamente preguntas y resuelve ideas de forma avanzada, mejora el código paso a paso y realiza la función de bloqueo distribuido con alta confiabilidad.

Inserte la descripción de la imagen aquí

Utilice el comando redis set con el parámetro NX (no existe) para realizar el bloqueo distribuido

NX: solo cuando no existe, se puede configurar; el conjunto exitoso devolverá OK, no exitoso devuelve null
Inserte la descripción de la imagen aquí

//分布式锁
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
    
    

    //1、占分布式锁。去redis占坑
    Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("lock", "lock");
    if(aBoolean){
    
    
        //加锁成功 执行业务
        Map<String, List<Catelog2Vo>> dataFromDB = this.getDataFromDB();
        //删除锁
        stringRedisTemplate.delete("lock");
        return dataFromDB;
    }else {
    
    
        //加锁失败   重试 自旋
        return getCatalogJsonFromDBWithRedisLock();
    }
}

Fase dos independiente más el tiempo de caducidad del bloqueo distribuido

Inserte la descripción de la imagen aquí

//分布式锁
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
    
    

    //1、占分布式锁。去redis占坑
    Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("lock", "lock");
    if(aBoolean){
    
    
        //加锁成功 执行业务
        //2、设置过期时间
        stringRedisTemplate.expire("lock",30, TimeUnit.SECONDS);
        Map<String, List<Catelog2Vo>> dataFromDB = this.getDataFromDB();
        //删除锁
        stringRedisTemplate.delete("lock");
        return dataFromDB;
    }else {
    
    
        //加锁失败   重试 自旋
        return getCatalogJsonFromDBWithRedisLock();
    }
}

Fase tres bloqueo atómico y tiempo de expiración establecido

Inserte la descripción de la imagen aquí

//分布式锁
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
    
    

    //1、占分布式锁。去redis占坑  并设置过期时间 必须是同步的 原子的
    Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("lock", "lock",30,TimeUnit.SECONDS);
    if(aBoolean){
    
    
        //加锁成功 执行业务
        Map<String, List<Catelog2Vo>> dataFromDB = this.getDataFromDB();
        //删除锁
        stringRedisTemplate.delete("lock");
        return dataFromDB;
    }else {
    
    
        //加锁失败   重试 自旋
        return getCatalogJsonFromDBWithRedisLock();
    }
}

Fase 4 eliminar bloqueo para coincidencia de uuid de permisos

Inserte la descripción de la imagen aquí

//分布式锁
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
    
    

    //1、占分布式锁。去redis占坑  并设置过期时间 必须是同步的 原子的
    String uuid = UUID.randomUUID().toString();
    Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("lock",uuid,30,TimeUnit.SECONDS);
    if(aBoolean){
    
    
        //加锁成功 执行业务
        Map<String, List<Catelog2Vo>> dataFromDB = this.getDataFromDB();
        String lock = stringRedisTemplate.opsForValue().get("lock");
        if(uuid.equals(lock)){
    
    
            //删除自己的锁
            stringRedisTemplate.delete("lock");
        }
        return dataFromDB;
    }else {
    
    
        //加锁失败   重试 自旋
        return getCatalogJsonFromDBWithRedisLock();
    }
}

Operación atómica de bloqueo de eliminación de script Lua de fase 5

Inserte la descripción de la imagen aquí

//分布式锁
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
    
    

    //1、占分布式锁。去redis占坑  并设置过期时间 必须是同步的 原子的
    String uuid = UUID.randomUUID().toString();
    Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("lock",uuid,30,TimeUnit.SECONDS);
    if(aBoolean){
    
    
        //加锁成功 执行业务
        Map<String, List<Catelog2Vo>> dataFromDB = this.getDataFromDB();
        //获取值 + 对比 + 删除 必须是原子操作  lua脚本解锁
        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                "then " +
                "   return  redis.call('del', KEYS[1])" +
                "else " +
                "   return 0 " +
                "end";
        Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(luaScript, Long.class), Arrays.asList("lock"), uuid);
        
        return dataFromDB;
    }else {
    
    
        //加锁失败   重试 自旋
        return getCatalogJsonFromDBWithRedisLock();
    }
}

Resultado final de la fase 6

Independientemente de que el negocio se complete correctamente, elimine los bloqueos establecidos por usted mismo

    //分布式锁
    public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedisLock() {
    
    

        //1、占分布式锁。去redis占坑  并设置过期时间 必须是同步的 原子的
        String uuid = UUID.randomUUID().toString();
        Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("lock",uuid,300,TimeUnit.SECONDS);
        if(aBoolean){
    
    
            //加锁成功 执行业务
            Map<String, List<Catelog2Vo>> dataFromDB = null;
            try {
    
    
                dataFromDB = this.getDataFromDB();
            }finally {
    
    
                //获取值 + 对比 + 删除 必须是原子操作  lua脚本解锁
                String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                        "then " +
                        "   return  redis.call('del', KEYS[1])" +
                        "else " +
                        "   return 0 " +
                        "end";
                Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(luaScript, Long.class), Arrays.asList("lock"), uuid);
            }
            return dataFromDB;
        }else {
    
    
            //加锁失败   重试 自旋
            //睡眠
            try {
    
    
                Thread.sleep(200);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            return getCatalogJsonFromDBWithRedisLock();
        }
    }

Utilice el marco de Redisson para implementar bloqueos distribuidos

Si usa redis manualmente para implementar bloqueos distribuidos, debe escribir declaraciones de desbloqueo atómico de script lua y bloqueo atómico antes de cada proceso comercial, lo cual es demasiado engorroso, y el marco de uso de bloqueos distribuidos de Redisson puede ser más conveniente de implementar. La capa inferior de Reddison implementa el paquete JUC Por lo tanto, se puede conectar sin problemas al uso de JUC.

Introducir dependencias

<!--引入redis的分布式锁  分布式对象框架redison-->
      <dependency>
          <groupId>org.redisson</groupId>
          <artifactId>redisson</artifactId>
          <version>3.12.0</version>
      </dependency>

Configurar el cliente redissonClient

@Configuration
public class MyRedissonConfig {
    
    
    /**
     * 所有对Redisson的使用 都是通过RedissonClient对象
     * @return
     * @throws IOException
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() throws IOException{
    
    
        //1、创建配置   redisson包下的config
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.231.1:6379");
        //2、根据config创建出RedissonClient示例
        return Redisson.create(config);
    }
}

Utilice bloqueos redisson para implementar bloqueos distribuidos

//分布式锁
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDBWithRedissonLock() {
    
    

    //1、占分布式锁。redisson
    /**
     * 锁的名字 决定了锁的粒度,越细越快
     * 锁的粒度约定:  具体缓存的是某个数据  例如 11号商品  product-11-lock
     */
    RLock lock = redissonClient.getLock("catalogJson-lock");
    lock.lock();
    Map<String, List<Catelog2Vo>> dataFromDB = null;
    try{
    
    
        //加锁成功 执行业务
        dataFromDB = this.getDataFromDB();
    }finally{
    
    
        lock.unlock();
    }
    return dataFromDB;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_44634197/article/details/108308395
Recomendado
Clasificación