您的位置:首页 > 数据库 > Redis

redis实现分布式锁

2016-01-14 16:41 896 查看
使用redis实现分布式锁比zookeeper简单

关于分布式锁的存活性和安全性的保证:

1.安全性:互斥现象在。在任何时候都应该仅仅有一个client hold a lock。 

2.存活性A:死锁的释放。很多时候可能获得一个锁,即使client锁住的资源挂了或者只得到资源的部分。 

3.存活性B:容错能力。尽可能的redis核心的node是正常工作的,clients能够得到和释放锁。 

第一点是通过只有持有锁的client才能执行任务

第二点是通过redis中key的过期时间来保证

第三点如果单台redis的master需要有一定的容错能力

使用redis实现分布式锁实际上是使用了redis的key-value的超时机制,以及租约机制。

1、定义redis缓冲key,lockKey,并设置超时时间N秒,使用redis的SETNX方法

2、多台客户端机器client定时每M秒获取锁,并且每台client的锁对应的value都是唯一的

3、如果client获取锁时候发现所已经存在,说明锁被其它的client持有

4、如果持有lockkey的client注册租约失败,并且超过N秒,则利用redis的超时机制,自动删除lockKey,这时候其它的client可以抢占lockkey

private void setLeaseLock() {
for (LockMessage lockMessage : lockMap.values()) {
try {
// 锁已过期,尝试nx操作获取锁
if (System.currentTimeMillis() >= lockMessage.getExpireTime()) {
String isOk = cacheclient.setString(lockMessage.getKey(), 
lockMessage.getValue(), "NX", "EX", LEASE_EXPIRE_TIME);
if (isOk != null && isOk.equals("OK")) {
lockMessage.setExpireTime(
System.currentTimeMillis() + (LEASE_EXPIRE_TIME * 1000L));
}
// 如果NX不能获取锁,需要进一步确认此锁是否还属于自己
// 如果属于自己,则取出当前锁的TTL赋给内存对象
else if (isOk == null) {
String serverLockMessage = cacheclient.getString(lockMessage.getKey());
if (serverLockMessage != null && serverLockMessage.equals(lockMessage.getValue())) {
long ttl = cacheclient.ttl(lockMessage.getKey());
if (ttl > LEASE_PERIOD) {
lockMessage.setExpireTime(
System.currentTimeMillis() + (ttl * 1000L));
}
}
}

// 锁还未过期,尝试expire续租锁
else {
// 为了防止极端情况下锁正好过期 or 锁被其它节点抢走,需要确认锁是自己拥有的
// 如果锁不属于自己,则放弃续约
String serverLockMessage = cacheclient.getString(lockMessage.getKey());
if (serverLockMessage == null || !serverLockMessage.equals(lockMessage.getValue())) {
return;
}

long isOk = cacheclient.expire(
lockMessage.getKey(), (int)LEASE_EXPIRE_TIME);
if (isOk == 1L) {
lockMessage.setExpireTime(
System.currentTimeMillis() + (LEASE_EXPIRE_TIME * 1000L));
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}

以上如果业务比较简单,并且能容忍一定的错误可以使用,如果对安全性要求非常高,则不要使用

问题:

使用一台master、slave,这种模型的一种竞态条件:

1.客户端A在主节点获得了一个锁。

2.主节点挂了,而到从节点的写同步还没完成。

3.从节点被提升为主节点。

4.客户端B获得和A相同的锁。注意,锁安全性被破坏了!

解决这个问题,可以使用多个master同时来控制

方案:http://www.oschina.net/translate/redis-distlock
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  redis 分布式锁