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
关于分布式锁的存活性和安全性的保证:
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安装问题小结
- Redis偶发连接失败案例实战记录
- Redis中实现查找某个值的范围
- Redis和Memcached的区别详解
- 分割超大Redis数据库例子
- Redis总结笔记(一):安装和常用命令
- Redis sort 排序命令详解
- 用Redis实现微博关注关系
- redis中修改配置文件中的端口号 密码方法
- 在Ruby on Rails上使用Redis Store的方法
- Redis和Memcache的区别总结
- 在Node.js应用中使用Redis的方法简介
- Redis服务器的启动过程分析
- web 应用中常用的各种 cache详解
- 利用yum安装Redis的方法详解
- 从MySQL到Redis的简单数据库迁移方法
- 为啥懒 Redis 是更好的 Redis
- 利用Redis实现SQL伸缩的方法
- 在Redis数据库中实现分布式速率限制的方法
- PHP+redis实现添加处理投票的方法