RedLock是一种分布式锁的实现方式,算法思想很好理解:假设有N个相互独立无任何协作的Redis master,在每个master上使用单机Redis的加锁方式加锁。当有N/2+1个节点加锁成功,即获取分布式锁成功;否则在所有实例上解锁。
客户端行为
- 获取当前Unix时间,以毫秒为单位。
 
- 依次尝试从N个Master实例使用相同的key和随机值获取锁(假设这个key是LOCK_KEY)。当向Redis设置锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。
 
- 客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。
 
- 如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。
 
- 如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。  
参考:
 RedLock算法理解
 
使用场景
分布式锁说明
一般说的redis分布式锁,其实是针对多个客户端获取锁和释放锁,redis分布式锁需要保证操作的原子性。这种情况下的,一般一个redis集群中就只有1个master,分布式锁的获取只是单机操作(包括redisson的getLock)。
而如果是cluster集群模式,不同key分布在不同的master上;或者在哨兵模式集群之上加一次负载均衡,串联多个哨兵集群作为一个大集群。针对这种相互独立的多个Master,需要加上一个分布式锁的话,Redis官方推出了一个规范的算法:RedLock。
参考:
    Redis的三种集群模式  
通过jedis获取分布式锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
   | import redis.clients.jedis.Jedis; import redis.clients.jedis.params.SetParams; import java.util.Collections;
  public class RedisLock {
      private static final Long RELEASE_SUCCESS = 1L;     private static final String LOCK_SUCCESS = "OK";     private static final String KEY_PREFIX="DE_BATCH_LOCK_";
      
 
 
 
 
 
      public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
          String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";         Object result = jedis.eval(script, Collections.singletonList(KEY_PREFIX+lockKey), Collections.singletonList(requestId));         if (RELEASE_SUCCESS.equals(result)) {             return true;         }         return false;     }
 
      
 
 
 
 
 
 
      public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, Integer expireTime) {         SetParams params = SetParams.setParams().nx();         if (expireTime != null) {             params.ex(expireTime);         }         String result = jedis.set(KEY_PREFIX+lockKey, requestId, params);         if (LOCK_SUCCESS.equals(result)) {             return true;         }         String value=jedis.get(KEY_PREFIX+lockKey);         logger.error("try get lock failed,current value = " + value);         return false;     } }    
   | 
 
通过Redisson获取分布式锁
1 2 3 4
   | RedissonClient client = Redisson.create(config); RLock lock = getClient().getLock(lockKey); lock.tryLock(waitTime, leaseTime, unit);
 
   | 
 
基于Redisson的RedLock实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | RLock lock1 = redissonClient1.getLock(lockKey); RLock lock2 = redissonClient2.getLock(lockKey); RLock lock3 = redissonClient3.getLock(lockKey);
  RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3); boolean isLock; try {     isLock = redLock.tryLock(1, 10, TimeUnit.SECONDS);     if (isLock) {              } } catch (Exception e) {     e.printStackTrace(); } finally {     redLock.unlock(); }
   |