本文主要介绍 Redis 分布式锁误删问题的解决

场景一

1. 问题的产生情况一

因为业务阻塞,导致别人的锁被误删

2. 解决思路

获取锁的时候存入标识,释放锁的时候判断标识是否一致,一致可以释放锁,不一致不释放锁。

3. 解决代码

总体思路:

  • 获取锁的时候存入线程标识 , 用 UUID 表示 ()
  • 释放锁的时候,判断标识是否一致
public class SimpleRedisLock implements ILock{// 锁的 key 前缀private static final String KEY_PREFIX = "lock:";// 线程 id 的前缀private static final String ID_PREFIX = UUID.randomUUID().toString() + "-";// 锁的名字private String lockName;// 传入的 StringRedisTemplateprivate StringRedisTemplate stringRedisTemplate;public SimpleRedisLock(String lockName, StringRedisTemplate stringRedisTemplate) {this.lockName = lockName;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean tryLock(long timeoutSec) {// 获取当前线程标识String threadId = ID_PREFIX + Thread.currentThread().getId();// 获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+lockName, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success); // 防止自动拆箱时候出现空指针问题}@Overridepublic void unlock() {// 获取当前锁的线程 idString id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + lockName);// 获取当前请求释放锁的线程 idString threadId = ID_PREFIX + Thread.currentThread().getId();// 判断两者是否一致,一致给释放锁if(threadId.equals(id)){stringRedisTemplate.delete(KEY_PREFIX + lockName);}}
}



场景二

1. 问题的产生情况二

获取锁标识并判断一致后被阻塞导致误删问题

2. 解决思路

保证判断锁标识一致和删除锁这一操作的原子性

  1. Redis 事务:
  • 支持原子性,不支持一致性
  • 批处理操作,最终一致性 (基于乐观锁)
  1. Lua 脚本

Redis 提供了 Lua 脚本功能,在一个脚本中编写多条 Reids 命令,保证多条命令执行的原子性

https://www.runoob.com/lua/lua-tutorial.html

Redis 调用函数:

redis.call('命令名称', 'key', '其他参数')

Redis 执行脚本的命令:

eval "脚本语句"

eval 支持带参数脚本:

eval "return redis.call('set', KEYS[1], ARGV[1])" 1 name Rose

等价于 set name Rose

3. 解决代码

SpringBoot 整合 Lua 脚本实现锁的释放

释放锁的 Lua 脚本:

-- 获取锁中的线程标识
local id = redis.call('get, KEYS[1])
-- Redis中存入的线程标识和传入的参数一致可以删除
if(id == ARGV[1]) thenreturn redis.call('del', KEYS[1])
end
return 0

Java 执行 Lua 脚本:

public class SimpleRedisLock implements ILock{// 锁的 key 前缀private static final String KEY_PREFIX = "lock:";// 线程 id 的前缀private static final String ID_PREFIX = UUID.randomUUID().toString() + "-";// 锁的名字private String lockName;// 传入的 StringRedisTemplateprivate StringRedisTemplate stringRedisTemplate;private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static {UNLOCK_SCRIPT = new DefaultRedisScript<>();// 设置脚本位置UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));UNLOCK_SCRIPT.setResultType(Long.class);}public SimpleRedisLock(String lockName, StringRedisTemplate stringRedisTemplate) {this.lockName = lockName;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean tryLock(long timeoutSec) {// 获取当前线程标识String threadId = ID_PREFIX + Thread.currentThread().getId();// 获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+lockName, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success); // 防止自动拆箱时候出现空指针问题}@Overridepublic void unlock() {stringRedisTemplate.execute(UNLOCK_SCRIPT, Collections.singletonList(KEY_PREFIX + lockName), ID_PREFIX + Thread.currentThread().getId());}
}



总结

Redis 分布式锁实现思路:

  • 利用 setnx 获取锁,设置过期时间,保存 value 为线程标识
  • 释放锁时先判断线程标识是否一致,一致则删除锁

特性:

  • setnx 保证互斥性
  • 通过设置过期时间的方式,保证出现故障时锁仍然能释放,避免了死锁
  • 利用 Redis 集群保证高可用性和并发现


【Redis】Redis 分布式锁误删问题相关推荐

  1. Redis:基于SETNX解决分布式锁误删问题

    Redis:SETNX解决分布式锁误删问题 一.概述 二. 分布式锁(初级) (1)锁接口 (2)锁实现类+上锁 (3)释放锁 (4)存在的问题 三. 改进释放锁 (1)准备unlock.lua脚本 ...

  2. 《Redis官方文档》用Redis构建分布式锁

    <Redis官方文档>用Redis构建分布式锁 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现 ...

  3. 《Redis官方文档》用Redis构建分布式锁(悲观锁)

    2019独角兽企业重金招聘Python工程师标准>>> **用Redis构建分布式锁 ** 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章 ...

  4. Redis的分布式锁详解

    一.什么是分布式锁: 1.什么是分布式锁: 分布式锁,即分布式系统中的锁.在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题.与单体应用不同 ...

  5. Redis构建分布式锁——Redlock

    本文来自:http://ifeve.com/redis-lock/ 简介 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁 ...

  6. Redis 作者 Antirez 讲如何实现分布式锁?Redis 实现分布式锁天然的缺陷分析Redis分布式锁的正确使用姿势!...

    Redis分布式锁基本原理 采用 redis 实现分布式锁,主要是利用其单线程命令执行的特性,一般是 setnx, 只会有一个线程会执行成功,也就是只有一个线程能成功获取锁:看着很完美. 然而-- 看 ...

  7. Redis实现分布式锁的7种方案

    https://www.cnblogs.com/wangyingshuo/p/14510524.html 七种方案前言 日常开发中,秒杀下单.抢红包等等业务场景,都需要用到分布式锁.而Redis非常适 ...

  8. Redis实现分布式锁(SETNX)

    目录 1.什么是分布式锁 2.分布式锁应具备的条件 3.为什么使用分布式锁 4.SETNX介绍 5.分布式锁实现 6.效果演示 7.Redisson分布式锁详解 8.Lua脚本实现可重入分布式锁 1. ...

  9. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

最新文章

  1. 用jackson封装的JSON工具类
  2. xml语法规则(一)
  3. SD-WAN的四个价值—Vecloud微云
  4. 网工协议基础(1) OSI七层模型
  5. iOS开发点击UIButton实现UIView的旋转
  6. 2021牛客多校6 - Defend Your Country(点双缩点求割点)
  7. 注入双括号报错注入_SQL手动注入:sqlilabs(less110)
  8. 从挂科学渣到史上学历最低诺奖得主,他用17年时间重新证明自己
  9. 1Password 7:Mac的密码管理工具
  10. 解决升级PHP7后 微信公众号收不到消息
  11. 百度地图 城市中心点坐标
  12. Android 知识点 250 —— screencap截屏指令
  13. 集美福利!陈睿当时加入B站的故事分享
  14. 阿里云安全组规则授权对象设置为固定IP段访问
  15. Auto.js Pro安卓免ROOT引流脚本开发系列教程23网易公开课(1)-前言
  16. 基于飞凌i.MX6Q-C核心板搭建3D相机
  17. Spark GraphX下强连通子图和社团发现算法在1T TPC-DS数据集下执行方法、优化和性能估算
  18. 使用windows引导的ubuntu双操作系统
  19. 20201022-成信大-C语言程序设计-20201学期《C语言程序设计B》C-trainingExercises26
  20. git提示please tell me who you are

热门文章

  1. vue的生命周期 (11个钩子函数)看了都能懂的
  2. python绘制双折线图
  3. python plt 绘图,双轴设置刻度,步长,使用栅格,以base64格式输出
  4. 面向对象程序设计主要的三个特征
  5. captcha2 验证码 php,yii2.0-captcha验证码--详细设置
  6. mysql技术简介_mysql的简介和使用
  7. android 16进制颜色代码
  8. glup前端代码打包的使用
  9. C语言变量类型转换之float与int互相转换
  10. 微信退款接口(你们遇到的坑)