redis分布式锁

设计分布式锁应该考虑的东⻄:
排他性
在分布式应⽤集群中,同⼀个⽅法在同⼀时间只能被⼀台机器上的⼀个线程执⾏
容错性
分布式锁⼀定能得到释放,⽐如客户端奔溃或者⽹络中断
可重⼊、⾼性能、⾼可⽤
还需要注意分布式锁的开销、锁粒度
一般的写法:
1.加锁 SETNX key value
setnx 的含义就是 SET if Not Exists,有两个参数setnx(key, value),该方法是原子性操作,如果 key 不存在,则设置当前 key 成功,返回 1;如果当前 key 已经存在,则设置当前 key 失败,返回 0。
2.解锁 del (key)
得到锁的线程执⾏完任务,需要释放锁,以便其他线程可以进⼊,调⽤ del(key)
3配置锁超时 expire (key,30s)
客户端奔溃或者⽹络中断,资源将会永远被锁住,即死锁,因此需要给key配置过期时间,以保证即使没有被显式释放,这把锁也要在⼀定时间后⾃动释放.

String uuid = CommonUtil.generateUUID();
String lockKey = "lock:sku:"+skuId;
Boolean nativeLock = redisTemplate.opsForValue().setIfAbsent(lockKey,uuid,Duration.ofSeconds(30));
 if(nativeLock){
 	//加锁成功
 	try {
 		//执⾏业务 TODO
 	}finally {
 		String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
 		Integer result = redisTemplate.execute(newDefaultRedisScript<>(script, Integer.class),Arrays.asList(lockKey), uuid);
 	}
 }else {
 	//加锁失败,睡眠100毫秒,⾃旋重试
 	try {
		TimeUnit.MILLISECONDS.sleep(100L);
 	} catch (InterruptedException e){}
 	return addSku( skuId,skuCategory);
 }

保证查询操作和删除操作的原⼦性
一、使⽤lua脚本
1、在resources⽬录下创建unlock.lua,编辑脚本:

if redis.call("get",KEYS[1]) == ARGV[1] then
 return redis.call("del",KEYS[1])
else
 return 0
end

2、配置Bean加载lua脚本

@Bean
public DefaultRedisScript<List> defaultRedisScript(){
	 DefaultRedisScript<List> defaultRedisScript = new DefaultRedisScript<>();
 	defaultRedisScript.setResultType(List.class);
 	defaultRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("unlock.lua")));
 	return defaultRedisScript; 
 }

3、通过执⾏lua脚本解锁。

@AutoWired
private DefaultRedisScript defaultRedisScript;
//执⾏lua脚本
List<String> keys = new ArrayList<>();
keys.add(skuId);
List rs = stringRedisTemplate.execute(defaultRedisScript,keys,values.get(skuId));
System.out.println(rs.get(0));

二、看⻔狗机制
在这里插入图片描述
看⻔⼝线程:⽤于给当前 key 延⻓过期时间,保证业务线程正常执⾏的过程中,锁不会过期。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值