分布式锁的实现-Redisson

2017-08-15  本文已影响344人  xlesterx

常见3种分布式的实现比较

Redission

1. 简介

redission为redis官方推荐方式翻译,github地址。redisson-quick-start

2. 实现分析

2.1 解决的问题

安全和活跃性保证

任何时候只有一个客户端可以获得锁

  1. 死锁自由(即使一个客户端已经拥用了已损坏或已被分割资源的锁,但它也有可能请求其他的锁)

举例:竞态条件

客户端A在主节点获得了一个锁。
主节点挂了,而到从节点的写同步还没完成。
从节点被提升为主节点。
客户端B获得和A相同的锁。注意,锁安全性被破坏了!
  1. 容错(只要大部分Redis节点可用, 客户端就可以获得和释放锁)

3. 实现思路

3.1 单例演变

SET resource_name my_random_value NX PX 30000

解释:
设置key的值,仅当其不存在时生效(NX选项), 且设置其生存期为30000毫秒(PX选项)。和key关联的value值是"my_random_value"。这个值在所有客户端和所有加锁请求中是必须是唯一的

设置锁的超时时间
SET resource_name my_random_value NX PX 30000

获取锁 == myKey,释放
否则:return 0
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

实现

关键点

锁设计

// 检查是否key已经被占用,如果没有则设置超时时间和唯一标识,初始化value=1
if (redis.call('exists', key) == 0) 
then  
redis.call('hset', key, key-uunid, 1); //hset key field value
redis.call('pexpire', key, timeout);  //设置超时时间为毫秒
return null; 
end; 
// 如果锁重入,需要判断锁的key field 的情况 
if (redis.call('hexists', key, key-unuid) == 1) 
then 
redis.call('hincrby', key, key-unuid, 1);//使字段值增加指定的整数
redis.call('pexpire', key, timeout);//锁重入重新设置超时时间
return null; 
end; 
// 返回剩余的过期时间
return redis.call('pttl', key);
// 如果key已经不存在,说明已经被解锁,直接发布(publihs)redis消息
if (redis.call('exists', key) == 0) 
then
redis.call('publish', channelName, ARGV[1]);
    return 1;
end;
// key和field不匹配,说明当前客户端线程没有持有锁,不能主动解锁。
if (redis.call('hexists', key, key-uuid) == 0)
then 
    return null;
end; 
// 将value减1
local counter = redis.call('hincrby', key, key-uuid, -1); 
// 如果counter>0说明锁在重入,不能删除key
if (counter > 0)  
then
    redis.call('pexpire', key, timeout);                            
    return 0; 
else 
// 删除key并且publish 解锁消息
redis.call('del', key);                           
 redis.call('publish', channelName, ARGV[1]); 
return 1; 
end; 
return null;

Redisson源码解析

相关资料

分布式锁的几种实现方式
Redis实现分布式锁全局锁—Redis客户端Redisson中分布式锁RLock实现
基于Redis实现分布式锁,Redisson使用及源码分析

上一篇 下一篇

猜你喜欢

热点阅读