Redis分布式锁

参考 http://www.redis.cn/topics/distlock.html

单 Redis 实现分布式锁

获取锁命令

SET resource_name my_random_value NX PX 30000

仅当 key 不存在时才能执行成功(NX),并且设置了30秒的过期时间(PX).

key的值是一个随机值,这个值在每个客户端必须是唯一的

随机数的作用是为了安全的释放锁,仅当随机数等于本客户端村塾的值才能删除成功

Spring Boot 版本


@Slf4j
@SpringBootApplication
public class RedisApplication implements CommandLineRunner {

    String key = "k";
    ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
    @Autowired
    private RedisTemplate redisTemplate;

    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }

    @Override
    @SneakyThrows
    public void run(String... args) {
        boolean res = false;
        while (!res) {
            String v = UUID.randomUUID().toString();
            stringThreadLocal.set(v);
            log.info("uuid: {}", v);
            res = lock(stringThreadLocal.get());
            if (res) {
                log.info("设置锁成功");
                log.info("dosomething...");
                Thread.sleep(10000);
                relase(stringThreadLocal.get());
            } else {
                log.info("设置锁失败");
                Thread.sleep(1000);
            }
        }
    }

    public boolean lock(String value) {
        boolean res = redisTemplate.opsForValue().setIfAbsent(key, value, 60, TimeUnit.SECONDS);
        return res;
    }

    public void relase(String value) {
        Object o = redisTemplate.opsForValue().get(key);
        if (o != null && o instanceof String) {
            String v = String.class.cast(value);
            if (v.equals(stringThreadLocal.get())) {
                redisTemplate.delete(key);
                log.info("relase {}", v);
            }else{
                log.warn("失败 relase {}", v);
            }
        }
    }
}

使用 redisson

https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter

RLock lock = redisson.getLock("myLock");

// or wait for lock aquisition up to 100 seconds 
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
   try {
     ...
   } finally {
       lock.unlock();
   }
}

配置

https://github.com/redisson/redisson/wiki/2.-Configuration#26-single-instance-mode

参考配置

application.yml

spring:
  redis:
    #path to config - redisson.yaml
    redisson:
      file: classpath:redisson.yaml

redisson.yaml

singleServerConfig:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  password: null
  subscriptionsPerConnection: 5
  clientName: null
  address: "redis://himcs.io:6379"
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 24
  connectionPoolSize: 64
  database: 0
  dnsMonitoringInterval: 5000
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"
Last Updated:
Contributors: himcs