当前位置: 首页 > news >正文

Redis 分布式锁存在什么问题 ?如何解决 ?

目录

1. 如何实现分布式锁

2. Redis 分布式锁存在什么问题

2.1 解决死锁问题

2.2 解决锁误删问题


1. 如何实现分布式锁

Redis 天生就可以作为一个分布式系统来使用,所以它实现的锁都是分布式锁。

Redis 可以通过 setnx(set if not exists)命令实现分布式锁~

  • setnx mylock true  -  加锁
  • del mylock  -  释放锁

通过执行结果是否为 1 可以判断是否成功获取到锁~

2. Redis 分布式锁存在什么问题

Redis 分布式锁存在两个问题:

1.死锁问题:未设置过期时间锁忘记释放加锁后还没来的及释放锁就宕机了都会导致死锁问题.

2. 锁误删问题:设置了超时时间,但是线程执行超过超时时间后锁误删问题.

2.1 解决死锁问题

        MySQL 中解决死锁问题是通过设置超时时间,Redis 也是如此,但是问题来了,第一步先加锁,然后再设置超时时间,那么就不满足原子性了,那么怎么办 ?

        官方在 Redis 2.6.12 版本之后,新增了一个功能,我们可以使用一条命令既执行加锁操作,又设置超时时间:setnx expire

  • 第一条命令成功加锁,并设置 30 s 过期时间
  • 第二条命令跟在第一条命令后,还没有超过 30s,所以获取失败

2.2 解决锁误删问题

锁误删问题是解决死锁问题带来的问题,如何理解 ?

既然知道了什么是锁误删问题,那么如何解决 ?

答:可以通过添加锁标识来解决.

        前面我们使用 set 命令的时候,只使用到了 key,那么可以给 value 设置一个标识,表示当前锁归属于那个线程,例如 value=thread1,value=thread2.....

但是这样解决依然存在问题,因为新增锁标识之后,线程在释放锁的时候,需要执行两步操作了:

  1. 判断锁是否属于自己
  2. 如果是,就删除锁

这样就不能保证原子性了,那该怎么办?

【解决方案】

  1. 使用 lua 脚本来解决 (Redis 本身就能保证 lua 脚本里面所有命令都是原子性操作)
  2. 使用 Redisson 框架来解决(主流)

那么 Redisson 如何实现分布式锁呢 ?

【代码示例】

1.引入 Redisson 依赖

<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.23.2</version>
</dependency>

2.创建 RedissonClient 对象

@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");// 如果有密码需要设置密码return Redisson.create(config);}
}

3.调用分布式锁

@RestController
public class LockController {@Resourceprivate RedissonClient redissonClient;@RequestMapping("/lock")public String lockResource() throws InterruptedException {String lockKey = "myLock";// 获取锁RLock lock = redissonClient.getLock(lockKey);try {// 超时时间 10s, [tryLock 获取成功才需要释放锁,获取失败不需要释放锁]boolean isLocked = lock.tryLock(20, TimeUnit.SECONDS);if(isLocked) {// 成功获取到锁try {TimeUnit.SECONDS.sleep(5);return "成功获取到锁,并执行业务代码";} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.unlock();}} else {// 获取锁失败return "获取锁失败";}} catch (InterruptedException e) {e.printStackTrace();}return "获取锁成功";}
}

启动项目,使用 8080 端口访问接口:

 


http://www.lryc.cn/news/137041.html

相关文章:

  • n5173b是德科技keysight N5173B信号发生器
  • React源码解析18(10)------ 实现多节点的Diff算法
  • Linux指令篇!
  • Vue2学习笔记のVue组件化编程
  • 跨境电商儿童沙画办理EN71测试标准
  • chrome浏览器账号密码输入框自动填充时背景色不变
  • 【ARM】Day9 cortex-A7核I2C实验(采集温湿度)
  • 【Leetcode】移动零
  • 数据结构入门 — 顺序表详解
  • SimpleCG绘图函数(9)--绘制各种线条
  • RISCV 6 RISC-V加载存储指令
  • 木叶飞舞之【机器人ROS2】篇章_第二节、turtlebot3安装
  • 【论文阅读】自动驾驶安全的研究现状与挑战
  • 标签打印小工具 选择图片打印,按实际尺寸打印。可旋转图片
  • 什么是深拷贝和浅拷贝?
  • 安装docker服务及docker基本操作
  • 【项目经验】:项目中下拉框数据太多造成页面卡顿(二)
  • Prompt本质解密及Evaluation实战(一)
  • linux 在系统已有python2版本下安装python3
  • IO多路转接 ——— select、poll、epoll
  • FPGA原理与结构——FIFO IP核原理学习
  • 【Linux操作系统】Linux中的信号回收:管理子进程的关键步骤
  • Spark大数据分析与实战笔记(第一章 Scala语言基础-1)
  • R语言03-R语言中的矩阵
  • “深入理解JVM:探索Java虚拟机的工作原理与优化技巧“
  • SQL注入原理
  • PIL.Image和base64,格式互转
  • vue父子组件传值(v-model)
  • Java接口详解
  • Windows共享文件夹,用户密码访问