当前位置: 代码迷 >> 综合 >> 20-Redis6-分布式锁
  详细解决方案

20-Redis6-分布式锁

热度:99   发布时间:2023-10-24 06:48:31.0

参考链接:https://www.bilibili.com/video/BV1Rv41177Af?p=43&spm_id_from=pageDriver


 


1、刚开始 可以使用sexnx   这个命令上锁。。。使用完毕删除该key释放锁

2、使用setnx出现问题,使用sexnx一直不释放锁。怎么办?可以给锁加一个过期时间。

3、使用setnx 之后,准备设置过期时间。但是不能设置过期时间。怎么办?同时上锁的时候,同时设置过期时间      set key1 vvvv1 nx ex 12  #设置key1 值是vvvv1 过期时间是12秒

4、锁的释放问题

5、锁的UUID一样之后,还能删锁问题

6、锁的特点

互斥性:相互互斥

不发生死锁

各自释放各自的锁

加锁解锁有原子性

 

 

 


先测试1:加锁操作值释放锁。没有获得锁就等待

application.properties

spring.redis.cluster.nodes=192.168.181.138:7001, 192.168.181.138:7002,192.168.181.138:7003,192.168.181.138:7004,192.168.181.138:7005,192.168.181.138:7006
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=5
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.shutdown-timeout=6000

config

@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Serializable>redisTemplate(LettuceConnectionFactory connectionFactory) {RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;}
}

controller

@Controller
public class DemoController {@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/block")@ResponseBodypublic void block(){Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");if(lock){Object value = redisTemplate.opsForValue().get("num");if(StringUtils.isEmpty(value)){return;}int integer = Integer.valueOf(value+"");redisTemplate.opsForValue().set("num",integer+1);redisTemplate.delete("lock");String name = Thread.currentThread().getName();System.out.println(name+"设置成功");}else {try {Thread.sleep(100);String name = Thread.currentThread().getName();System.out.println(name+"开始进入等待======");block();} catch (InterruptedException e) {e.printStackTrace();}}}
}

测试:

1、先在redis中  set num  0

2、linux安装ab工具:  yum -y install httpd-tools    #安装ab工具     ab -V 查看版本

3、启动服务,开始测试     

      #测试命令      ab -n 1000 -c 100 http://192.168.124.8:8080/block     

    -c100 表示并发用户数为100

  -n1000 表示请求总数为1000

查看结果:

  在redis中  get num     #输出num的值是1000


在测试2,使用setnx出现问题,使用sexnx一直不释放锁。怎么办?可以给锁加一个过期时间。

application.properties

spring.redis.cluster.nodes=192.168.181.138:7001, 192.168.181.138:7002,192.168.181.138:7003,192.168.181.138:7004,192.168.181.138:7005,192.168.181.138:7006
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=5
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.shutdown-timeout=6000

config

@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Serializable>redisTemplate(LettuceConnectionFactory connectionFactory) {RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;}
}

controller

@Controller
public class DemoController {@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/block")@ResponseBodypublic void block(){
//设置10秒key过期Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111",10, TimeUnit.SECONDS);if(lock){Object value = redisTemplate.opsForValue().get("num");if(StringUtils.isEmpty(value)){return;}int integer = Integer.valueOf(value+"");redisTemplate.opsForValue().set("num",integer+1);redisTemplate.delete("lock");String name = Thread.currentThread().getName();System.out.println(name+"设置成功");}else {try {Thread.sleep(100);String name = Thread.currentThread().getName();System.out.println(name+"开始进入等待======");block();} catch (InterruptedException e) {e.printStackTrace();}}}}

4、锁的释放问题

20-Redis6-分布式锁

0、abc是多个应用。需要操作同一个锁

1、a先操作、上锁成功、具体操作、操作过程中服务器卡顿等。。。锁的时间到了,自动释放

2、b抢到了锁,b开始上锁成功,b开始具体操作,md,现在a居然又正常了,执行代码释放锁。会把b的锁给释放掉

解决方案:

20-Redis6-分布式锁

controller

package com.nuc.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.UUID;
import java.util.concurrent.TimeUnit;@Controller
public class DemoController {@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/block")@ResponseBodypublic void block(){String uuid =UUID.randomUUID().toString();Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,10, TimeUnit.SECONDS);if(lock){Object value = redisTemplate.opsForValue().get("num");if(StringUtils.isEmpty(value)){return;}int integer = Integer.valueOf(value+"");redisTemplate.opsForValue().set("num",integer+1);if(uuid.equals(redisTemplate.opsForValue().get("lock"))){redisTemplate.delete("lock");String name = Thread.currentThread().getName();System.out.println(name+"设置成功");}}else {try {Thread.sleep(100);String name = Thread.currentThread().getName();System.out.println(name+"开始进入等待======");block();} catch (InterruptedException e) {e.printStackTrace();}}}
}

5、锁的UUID一样之后,还能删锁问题

1、a上锁、具体操作、释放锁的时候先比较uui,发现uuid一样。开始删除的时候卡顿了。或锁的过期时间到了自动释放锁

2、在a卡顿或释放锁的时候b获得了锁,开始了具体操作

3、a卡顿之后要开始删除锁。导致a释放了b的锁。。

20-Redis6-分布式锁

 

解决方案:加入lua脚本

20-Redis6-分布式锁

20-Redis6-分布式锁