基于redis 实现分布式锁的方案
2016-12-26 17:31
761 查看
问题起源:
在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题。如果在库存操作上,加锁就可以避免库存卖超的问题。分布式锁使分布式系统之间同步访问共享资源的一种方式
基于redis实现分布式锁的原理:
redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX,GETSET,可以方便实现分布式锁机制
SETNX key value
功能:当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。
GETSET key value
功能:将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回null
实现要点:
1、避免死锁,必要的超时机制。设置时间戳,时间戳要精确到毫秒。如果获取锁失败,则说明锁被其他对象保持,检查其是否超时
2、释放锁时,避免释放非自己获得的锁,释放锁时,可以做一个是否超时的检查,如果超时说明锁就无需释放了
3、为了造成不必要的资源浪费,提高并发,最好在最小颗粒度上的块加锁
4、为了降低redis 压力,获取锁尝试时,循环之间一定要做sleep操作
参考源代码如下
// redis client
private Redistemplate tradeRedisTemplate
private Boolean setNX(String key, String value){
return redisConnection.setNX(key.bytes, value.bytes)
}
private String getSet(String key, String value){
byte[] result = redisConnection.getSet(key.bytes, value.bytes)
return new String(result)
}
//释放锁 key 锁名称,time 超时时间
public Void delDistributedLock(String key, Long time){
String lastTimeS = tradeRedisTemplate.opsForValue().get(key)
if(System.currentTimeMillis() - Long.parseLong(lastTimeS) < time){//避免删除非自己获取得到的锁
tradeRedisTemplate.delete(key)
}
}
//加锁 key 锁名称,time 超时时间
public Boolean acquireDistributedLock(String key, Long time){
if(setNX(key, Long.toString(System.currentTimeMillis()))){ //SETNX成功,则成功获取一个锁
return true
}else{
//SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时
String lastTimeS = tradeRedisTemplate.opsForValue().get(key)
Long lastTime = Long.parseLong(lastTimeS)
//超时
if(System.currentTimeMillis() - lastTime > time){
String lastTimeRedis = getSet(key, Long.toString(System.currentTimeMillis()))
if(lastTimeRedis.equals(lastTimeS)){// 获取锁成功
return true
}
// 已被其他进程捷足先登了
}
}
return false
}
参考资料:
http://redis.io/commands/setnx
http://www.blogjava.NET/caojianhua/archive/2013/01/28/394847.html
在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题。如果在库存操作上,加锁就可以避免库存卖超的问题。分布式锁使分布式系统之间同步访问共享资源的一种方式
基于redis实现分布式锁的原理:
redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX,GETSET,可以方便实现分布式锁机制
SETNX key value
功能:当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0。
GETSET key value
功能:将给定 key 的值设为 value ,并返回 key 的旧值 (old value),当 key 存在但不是字符串类型时,返回一个错误,当key不存在时,返回null
实现要点:
1、避免死锁,必要的超时机制。设置时间戳,时间戳要精确到毫秒。如果获取锁失败,则说明锁被其他对象保持,检查其是否超时
2、释放锁时,避免释放非自己获得的锁,释放锁时,可以做一个是否超时的检查,如果超时说明锁就无需释放了
3、为了造成不必要的资源浪费,提高并发,最好在最小颗粒度上的块加锁
4、为了降低redis 压力,获取锁尝试时,循环之间一定要做sleep操作
参考源代码如下
// redis client
private Redistemplate tradeRedisTemplate
private Boolean setNX(String key, String value){
return redisConnection.setNX(key.bytes, value.bytes)
}
private String getSet(String key, String value){
byte[] result = redisConnection.getSet(key.bytes, value.bytes)
return new String(result)
}
//释放锁 key 锁名称,time 超时时间
public Void delDistributedLock(String key, Long time){
String lastTimeS = tradeRedisTemplate.opsForValue().get(key)
if(System.currentTimeMillis() - Long.parseLong(lastTimeS) < time){//避免删除非自己获取得到的锁
tradeRedisTemplate.delete(key)
}
}
//加锁 key 锁名称,time 超时时间
public Boolean acquireDistributedLock(String key, Long time){
if(setNX(key, Long.toString(System.currentTimeMillis()))){ //SETNX成功,则成功获取一个锁
return true
}else{
//SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时
String lastTimeS = tradeRedisTemplate.opsForValue().get(key)
Long lastTime = Long.parseLong(lastTimeS)
//超时
if(System.currentTimeMillis() - lastTime > time){
String lastTimeRedis = getSet(key, Long.toString(System.currentTimeMillis()))
if(lastTimeRedis.equals(lastTimeS)){// 获取锁成功
return true
}
// 已被其他进程捷足先登了
}
}
return false
}
参考资料:
http://redis.io/commands/setnx
http://www.blogjava.NET/caojianhua/archive/2013/01/28/394847.html
相关文章推荐
- 分布式锁实现方案1、基于Redis的SETNX操作实现的分布式锁
- 基于 Redis 的分布式缓存实现方案及可靠性加固策略
- 分布式锁实现方案2、基于Redis的SET操作实现的分布式锁
- 缓存篇~第七回 Redis实现基于方法签名的数据集缓存(可控更新,分布式数据缓存)
- 基于Redis实现分布式消息队列(4)
- 基于Redis实现分布式锁以及任务队列
- 基于Redis实现分布式锁
- 基于Redis实现分布式锁
- 基于Redis实现分布式锁
- [转载] 基于Redis实现分布式消息队列
- 基于Redis实现分布式锁
- 基于Python,scrapy,redis的分布式爬虫实现框架
- 基于Redis实现简单的分布式锁
- 基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有测试代码(何志雄)
- 分布式架构下的会话追踪实践【基于Cookie和Redis实现】
- 基于nutcracker 的redis分布式缓存的实现的注意
- 基于Redis实现分布式消息队列(3)
- 基于Redis实现分布式锁
- 基于Redis实现分布式锁
- 基于Redis实现分布式锁,Redisson使用及源码分析